Commit e388b130 authored by Girish Ramakrishnan's avatar Girish Ramakrishnan

Migrate keys to new layout

move from username:devicename -> username/devicename
parent f168a263
......@@ -39,6 +39,7 @@
"ldapjs": "^1.0.2",
"mkdirp": "^0.5.1",
"morgan": "^1.9.0",
"safetydance": "^0.7.1",
"superagent": "^3.8.2",
"vue": "^2.5.16"
},
......
......@@ -7,6 +7,7 @@ const fs = require('fs')
const {HttpError} = require('connect-lastmile')
const Archiver = require('archiver')
const ldap = require('./ldap')
const safe = require('safetydance')
const promisify = (func) => (...args) => new Promise((resolve, reject) =>
func(...args, (err, res) => err ? reject(err) : resolve(res))
......@@ -132,11 +133,12 @@ const cleanUserName = userName => userName.toLowerCase().replace(/[^A-Za-z0-9.]+
const cleanDeviceName = deviceName => deviceName.replace(/[^A-Za-z0-9\-_]+/g, '')
const listUserKeys = (username) => readdir(keyDir)
.then(files => files.filter(file => file.startsWith(username + ':') && file.endsWith('.key')))
.then(files => Promise.all(files.map(file => stat(path.join(keyDir, file))))
const listUserKeys = (username) => readdir(path.join(keyDir, username))
.then(files => files.filter(file => file.endsWith('.key')))
.catch(() => []) // dir does not exist until a key is created
.then(files => Promise.all(files.map(file => stat(path.join(keyDir, username, file))))
.then(stats => files.map((fileName, i) => {
const deviceName = fileName.substring(username.length + 1, fileName.length).replace(/\.key/, '')
const deviceName = fileName.replace(/\.key/, '')
return {
name: deviceName,
hostname: `${deviceName}.${username}`,
......@@ -163,10 +165,13 @@ const createKey = (req, res, next) => {
listUserKeys(cleanUserName(req.session.user.username))
.then(list => {
if (list.map(e => e.name).includes(deviceName)) return next(new HttpError(409, 'Device already exists'))
safe.fs.mkdirSync(path.join(keyDir, cleanUserName(req.session.user.username))) // ensure directory
return spawnFile({
tag: 'createUserKey',
file: path.join(baseDir, 'pkitool'),
args: [`${cleanUserName(req.session.user.username)}:${deviceName}`]
args: [ path.join(keyDir, `${cleanUserName(req.session.user.username)}/${deviceName}`) ]
})
.then(() => res.status(201).send({created: deviceName}))
})
......@@ -200,8 +205,8 @@ const getKey = (req, res, next) => {
listUserKeys(cleanUserName(req.session.user.username))
.then(list => {
if (!list.map(e => e.name).includes(deviceName)) return next(new HttpError(404, 'Not Found'))
const certFile = `${cleanUserName(req.session.user.username)}:${deviceName}.crt`
const keyFile = `${cleanUserName(req.session.user.username)}:${deviceName}.key`
const certFile = `${cleanUserName(req.session.user.username)}/${deviceName}.crt`
const keyFile = `${cleanUserName(req.session.user.username)}/${deviceName}.key`
if (zip) {
res.header('Content-Type', 'application/zip')
......@@ -258,10 +263,10 @@ const revokeKey = (req, res, next) => {
return spawnFile({
tag: 'revokeUserKey',
file: path.join(baseDir, 'revoke-full'),
args: [`${cleanUserName(req.session.user.username)}:${deviceName}`],
args: [ path.join(keyDir, `${cleanUserName(req.session.user.username)}/${deviceName}`) ],
wantedCode: 2
})
.then(() => rm(path.join(keyDir, `${cleanUserName(req.session.user.username)}:${deviceName}.key`)))
.then(() => rm(path.join(keyDir, `${cleanUserName(req.session.user.username)}/${deviceName}.key`)))
.then(() => res.status(200).send({revoked: deviceName}))
})
.catch(error => next(new HttpError(500, error)))
......@@ -276,7 +281,7 @@ const onClientConnect = (req, res, next) => {
if (token !== ADMIN_TOKEN) return next(new HttpError(401, 'Unauthorized'))
if (!cn || !remoteIp || !vpnIp) return next(new HttpError(409, 'Invalid Request'))
const match = /^([A-Za-z0-9.]+):([A-Za-z0-9\-_]+)$/.exec(cn)
const match = /^.*\/([A-Za-z0-9.]+)\/([A-Za-z0-9\-_]+)$/.exec(cn) // cn is the full path of the key that matched
if (!match) return next(new HttpError(409, 'Invalid Request'))
const [, user, deviceName] = match
......@@ -301,7 +306,7 @@ const onClientDisconnect = (req, res, next) => {
if (token !== ADMIN_TOKEN) return next(new HttpError(401, 'Unauthorized'))
if (!cn) return next(new HttpError(409, 'Invalid Request'))
const match = /^([A-Za-z0-9.]+):([A-Za-z0-9\-_]+)$/.exec(cn)
const match = /^.*\/([A-Za-z0-9.]+)\/([A-Za-z0-9\-_]+)$/.exec(cn) // cn is the full path of the key that matched
if (!match) return next(new HttpError(409, 'Invalid Request'))
const [, user, deviceName] = match
......@@ -324,7 +329,7 @@ const onLearnAddress = (req, res, next) => {
if (operation.match(/^(add|update)$/) && !cn) return next(new HttpError(409, 'cn is required'))
if (operation === 'add' || operation === 'update') {
const match = /^([A-Za-z0-9.]+):([A-Za-z0-9\-_]+)$/.exec(cn)
const match = /^.*\/([A-Za-z0-9.]+)\/([A-Za-z0-9\-_]+)$/.exec(cn) // cn is the full path of the key that matched
if (!match) return next(new HttpError(409, 'Invalid Request'))
const [, user, deviceName] = match
......
......@@ -22,6 +22,15 @@ if [ ! -d /app/data/keys ]; then
openvpn --genkey --secret /app/data/keys/ta.key # OpenVPN static key
/app/code/easyrsa/build-dh
/app/code/easyrsa/pkitool --server cloudron # server key
else
echo "==> Migrate keys to new layout"
for file in `find /app/data/key/*:* -maxdepth 0 -type f -printf "%f\n"`; do
echo "==> moving $file"
username=$(cat $file | cut -d ":" -f 1)
devicename=$(cat $file | cut -d ":" -f 2)
mkdir -p /app/data/keys/${username}
mv $file /app/data/keys/${username}/${devicename}
done
fi
# initializing / regenerating CRL file
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment