Fix bug 366 (#764)
* Optimize DB * Clean up names * fixup! Clean up names * fixup! fixup! Clean up names
This commit is contained in:
parent
b4de9c23eb
commit
542be2c1e9
175 changed files with 8503 additions and 5587 deletions
98
backend/modules/users/apiTokenService.js
Normal file
98
backend/modules/users/apiTokenService.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
const crypto = require('crypto');
|
||||
const bcrypt = require('bcrypt');
|
||||
const { ApiToken } = require('../../models');
|
||||
|
||||
const TOKEN_PREFIX_LENGTH = 12;
|
||||
|
||||
const serializeApiToken = (tokenInstance) => {
|
||||
if (!tokenInstance) return null;
|
||||
const tokenJson = tokenInstance.toJSON();
|
||||
return {
|
||||
id: tokenJson.id,
|
||||
name: tokenJson.name,
|
||||
token_prefix: tokenJson.token_prefix,
|
||||
created_at: tokenJson.created_at,
|
||||
updated_at: tokenJson.updated_at,
|
||||
last_used_at: tokenJson.last_used_at,
|
||||
expires_at: tokenJson.expires_at,
|
||||
revoked_at: tokenJson.revoked_at,
|
||||
};
|
||||
};
|
||||
|
||||
const generateRawToken = () => `tt_${crypto.randomBytes(32).toString('hex')}`;
|
||||
|
||||
async function createApiToken({ userId, name, expiresAt, abilities = null }) {
|
||||
const rawToken = generateRawToken();
|
||||
const tokenHash = await bcrypt.hash(rawToken, 12);
|
||||
const tokenPrefix = rawToken.slice(0, TOKEN_PREFIX_LENGTH);
|
||||
|
||||
const tokenRecord = await ApiToken.create({
|
||||
user_id: userId,
|
||||
name: name || 'Personal Access Token',
|
||||
token_hash: tokenHash,
|
||||
token_prefix: tokenPrefix,
|
||||
abilities,
|
||||
expires_at: expiresAt || null,
|
||||
});
|
||||
|
||||
return { rawToken, tokenRecord };
|
||||
}
|
||||
|
||||
async function findValidTokenByValue(tokenValue) {
|
||||
if (!tokenValue) return null;
|
||||
const prefix = tokenValue.slice(0, TOKEN_PREFIX_LENGTH);
|
||||
const possibleTokens = await ApiToken.findAll({
|
||||
where: { token_prefix: prefix },
|
||||
order: [['created_at', 'DESC']],
|
||||
});
|
||||
|
||||
for (const token of possibleTokens) {
|
||||
if (token.revoked_at) continue;
|
||||
if (token.expires_at && token.expires_at < new Date()) continue;
|
||||
const match = await bcrypt.compare(tokenValue, token.token_hash);
|
||||
if (match) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function revokeApiToken(tokenId, userId) {
|
||||
const token = await ApiToken.findOne({
|
||||
where: { id: tokenId, user_id: userId },
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!token.revoked_at) {
|
||||
token.revoked_at = new Date();
|
||||
await token.save();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
async function deleteApiToken(tokenId, userId) {
|
||||
const token = await ApiToken.findOne({
|
||||
where: { id: tokenId, user_id: userId },
|
||||
});
|
||||
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await token.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createApiToken,
|
||||
revokeApiToken,
|
||||
deleteApiToken,
|
||||
findValidTokenByValue,
|
||||
serializeApiToken,
|
||||
TOKEN_PREFIX_LENGTH,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue