-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
201 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,61 @@ | ||
const crypto = require('crypto'); | ||
const Sequelize = require('sequelize'); | ||
const { sequelize } = require('./sequelize'); | ||
|
||
exports.AuthToken = sequelize.define('authTokens', { | ||
const AuthToken = sequelize.define('authTokens', { | ||
id: { | ||
type: Sequelize.STRING, | ||
primaryKey: true, | ||
}, | ||
data: { | ||
type: Sequelize.STRING | ||
}, | ||
encryptedData: { | ||
type: Sequelize.STRING | ||
}, | ||
}); | ||
|
||
function getCipherKey() { | ||
if (!process.env.APP_SERVER_SECRET_KEY) { | ||
throw new Error('APP_SERVER_SECRET_KEY is not defined'); | ||
} | ||
if (process.env.APP_SERVER_SECRET_KEY.length < 32) { | ||
// pad secret key with spaces if it is less than 32 bytes | ||
return process.env.APP_SERVER_SECRET_KEY.padEnd(32, ' '); | ||
} | ||
if (process.env.APP_SERVER_SECRET_KEY.length > 32) { | ||
// truncate secret key if it is more than 32 bytes | ||
return process.env.APP_SERVER_SECRET_KEY.slice(0, 32); | ||
} | ||
return process.env.APP_SERVER_SECRET_KEY; | ||
} | ||
|
||
const originalSave = AuthToken.prototype.save; | ||
AuthToken.prototype.save = async function () { | ||
if (this.data) { | ||
// encode data to encryptedData | ||
const cipher = crypto | ||
.createCipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0)) | ||
this.encryptedData = cipher.update(this.data, 'utf8', 'hex') + cipher.final('hex'); | ||
this.data = ''; | ||
} | ||
return originalSave.call(this); | ||
} | ||
|
||
AuthToken.prototype.getDecryptedData = function () { | ||
if (!this.encryptedData) { | ||
// for backward compatibility | ||
return this.data; | ||
} | ||
// decode encryptedData to data | ||
const decipher = crypto | ||
.createDecipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0)) | ||
return decipher.update(this.encryptedData, 'hex', 'utf8') + decipher.final('utf8'); | ||
} | ||
|
||
AuthToken.prototype.removeData = function () { | ||
this.data = ''; | ||
this.encryptedData = ''; | ||
} | ||
|
||
exports.AuthToken = AuthToken; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const { AuthToken } = require('../models/authToken'); | ||
const { errorLogger } = require('../utils/logger'); | ||
|
||
async function migrateEncryptedData(req, res) { | ||
if (!process.env.MAINTAIN_TOKEN) { | ||
res.status(404); | ||
res.send('Not found'); | ||
return; | ||
} | ||
if (req.query.maintain_token !== process.env.MAINTAIN_TOKEN) { | ||
res.status(401); | ||
res.send('Token invalid'); | ||
return; | ||
} | ||
try { | ||
const authTokens = await AuthToken.findAll(); | ||
for (const authToken of authTokens) { | ||
if (authToken.data) { | ||
await authToken.save(); | ||
} | ||
} | ||
res.status(200); | ||
res.send('migrated'); | ||
} catch (e) { | ||
errorLogger(e); | ||
res.status(500); | ||
res.send('internal error'); | ||
} | ||
} | ||
|
||
exports.migrateEncryptedData = migrateEncryptedData; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
const { AuthToken } = require('../src/server/models/authToken'); | ||
|
||
describe('authToken', () => { | ||
it('should create auth token with encrypted data', async () => { | ||
const authToken = await AuthToken.create({ | ||
id: '123', | ||
data: 'test', | ||
}); | ||
expect(authToken.encryptedData).not.toBe(''); | ||
expect(authToken.data).toBe(''); | ||
|
||
const savedAuthToken = await AuthToken.findByPk('123'); | ||
expect(savedAuthToken.data).toBe(''); | ||
expect(savedAuthToken.getDecryptedData()).toBe('test'); | ||
expect(savedAuthToken.encryptedData).not.toBe(''); | ||
await savedAuthToken.destroy(); | ||
}); | ||
|
||
it('should create auth token without data', async () => { | ||
const authToken = await AuthToken.create({ | ||
id: '123', | ||
}); | ||
expect(authToken.encryptedData).toBe(undefined); | ||
expect(authToken.data).toBe(undefined); | ||
|
||
const savedAuthToken = await AuthToken.findByPk('123'); | ||
expect(savedAuthToken.data).toBe(null); | ||
expect(savedAuthToken.getDecryptedData()).toBe(null); | ||
expect(savedAuthToken.encryptedData).toBe(null); | ||
await savedAuthToken.destroy(); | ||
}); | ||
|
||
it('should get decoded data successfully', async () => { | ||
const authToken = await AuthToken.create({ | ||
id: '123', | ||
encryptedData: 'cfe2148b1b5236137f58348954930ba6', | ||
}); | ||
expect(authToken.getDecryptedData()).toBe('test'); | ||
await authToken.destroy(); | ||
}); | ||
|
||
it('should remove auth token data successfully', async () => { | ||
const authToken = await AuthToken.create({ | ||
id: '123', | ||
data: 'test', | ||
}); | ||
authToken.removeData(); | ||
await authToken.save(); | ||
|
||
const savedAuthToken = await AuthToken.findByPk('123'); | ||
expect(savedAuthToken.data).toBe(''); | ||
expect(savedAuthToken.encryptedData).toBe(''); | ||
expect(savedAuthToken.getDecryptedData()).toBe(''); | ||
await savedAuthToken.destroy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
const request = require('supertest'); | ||
const { server } = require('../src/server'); | ||
const { AuthToken } = require('../src/server/models/authToken'); | ||
describe('Maintain', () => { | ||
it('should return 404 if MAINTAIN_TOKEN is not set', async () => { | ||
const res = await request(server).get('/maintain/migrate-encrypted-data'); | ||
expect(res.status).toBe(404); | ||
expect(res.text).toBe('Not found'); | ||
}); | ||
|
||
it('should return 401 if maintain_token is invalid', async () => { | ||
process.env.MAINTAIN_TOKEN = 'maintain_token_xxx'; | ||
const res = await request(server).get('/maintain/migrate-encrypted-data?maintain_token=invalid'); | ||
expect(res.status).toBe(401); | ||
expect(res.text).toBe('Token invalid'); | ||
}); | ||
|
||
it('should return 200 if maintain_token is valid', async () => { | ||
process.env.MAINTAIN_TOKEN = 'maintain_token_xxx'; | ||
const res = await request(server).get(`/maintain/migrate-encrypted-data?maintain_token=${process.env.MAINTAIN_TOKEN}`); | ||
expect(res.status).toBe(200); | ||
expect(res.text).toBe('migrated'); | ||
}); | ||
|
||
it('should migrate encrypted data', async () => { | ||
await AuthToken.create({ | ||
id: '1111', | ||
data: 'test1', | ||
}); | ||
await AuthToken.create({ | ||
id: '2222', | ||
}); | ||
const authToken = await AuthToken.findByPk('2222'); | ||
await authToken.update({ | ||
data: 'test', | ||
}); | ||
await request(server).get(`/maintain/migrate-encrypted-data?maintain_token=${process.env.MAINTAIN_TOKEN}`); | ||
const authToken1 = await AuthToken.findByPk('1111'); | ||
const authToken2 = await AuthToken.findByPk('2222'); | ||
expect(authToken1.data).toBe(''); | ||
expect(authToken1.getDecryptedData()).toBe('test1'); | ||
expect(authToken2.data).toBe(''); | ||
expect(authToken2.getDecryptedData()).toBe('test'); | ||
await authToken1.destroy(); | ||
await authToken2.destroy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters