mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
182 lines
5.8 KiB
JavaScript
182 lines
5.8 KiB
JavaScript
import { deleteByName } from '@/utils/database';
|
|
import { ENV } from '@/vendor/open-api';
|
|
import { TOKENS_KEY, SUBS_KEY, FILES_KEY, COLLECTIONS_KEY } from '@/constants';
|
|
import { failed, success } from '@/restful/response';
|
|
import $ from '@/core/app';
|
|
import { RequestInvalidError, InternalServerError } from '@/restful/errors';
|
|
|
|
export default function register($app) {
|
|
if (!$.read(TOKENS_KEY)) $.write([], TOKENS_KEY);
|
|
|
|
$app.post('/api/token', signToken);
|
|
|
|
$app.route('/api/token/:token').delete(deleteToken);
|
|
|
|
$app.route('/api/tokens').get(getAllTokens);
|
|
}
|
|
|
|
function deleteToken(req, res) {
|
|
let { token } = req.params;
|
|
token = decodeURIComponent(token);
|
|
$.info(`正在删除:${token}`);
|
|
let allTokens = $.read(TOKENS_KEY);
|
|
deleteByName(allTokens, token, 'token');
|
|
$.write(allTokens, TOKENS_KEY);
|
|
success(res);
|
|
}
|
|
|
|
function getAllTokens(req, res) {
|
|
const { type, name } = req.query;
|
|
const allTokens = $.read(TOKENS_KEY) || [];
|
|
success(
|
|
res,
|
|
type || name
|
|
? allTokens.filter(
|
|
(item) =>
|
|
(type ? item.type === type : true) &&
|
|
(name ? item.name === name : true),
|
|
)
|
|
: allTokens,
|
|
);
|
|
}
|
|
|
|
async function signToken(req, res) {
|
|
if (!ENV().isNode) {
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_ENV',
|
|
`This endpoint is only available in Node.js environment`,
|
|
),
|
|
);
|
|
}
|
|
try {
|
|
const { payload, options } = req.body;
|
|
const ms = eval(`require("ms")`);
|
|
let token = payload?.token;
|
|
if (token != null) {
|
|
if (typeof token !== 'string' || token.length < 1) {
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_CUSTOM_TOKEN',
|
|
`Invalid custom token: ${token}`,
|
|
),
|
|
);
|
|
}
|
|
const tokens = $.read(TOKENS_KEY) || [];
|
|
if (tokens.find((t) => t.token === token)) {
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'DUPLICATE_TOKEN',
|
|
`Token ${token} already exists`,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
const type = payload?.type;
|
|
const name = payload?.name;
|
|
if (!type || !name)
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_PAYLOAD',
|
|
`payload type and name are required`,
|
|
),
|
|
);
|
|
if (type === 'col') {
|
|
const collections = $.read(COLLECTIONS_KEY) || [];
|
|
const collection = collections.find((c) => c.name === name);
|
|
if (!collection)
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_COLLECTION',
|
|
`collection ${name} not found`,
|
|
),
|
|
);
|
|
} else if (type === 'file') {
|
|
const files = $.read(FILES_KEY) || [];
|
|
const file = files.find((f) => f.name === name);
|
|
if (!file)
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_FILE',
|
|
`file ${name} not found`,
|
|
),
|
|
);
|
|
} else if (type === 'sub') {
|
|
const subs = $.read(SUBS_KEY) || [];
|
|
const sub = subs.find((s) => s.name === name);
|
|
if (!sub)
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_SUB',
|
|
`sub ${name} not found`,
|
|
),
|
|
);
|
|
} else {
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_TYPE',
|
|
`type ${name} not supported`,
|
|
),
|
|
);
|
|
}
|
|
let expiresIn = options?.expiresIn;
|
|
if (options?.expiresIn != null) {
|
|
expiresIn = ms(options.expiresIn);
|
|
if (expiresIn == null || isNaN(expiresIn) || expiresIn <= 0) {
|
|
return failed(
|
|
res,
|
|
new RequestInvalidError(
|
|
'INVALID_EXPIRES_IN',
|
|
`Invalid expiresIn option: ${options.expiresIn}`,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
// const secret = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH');
|
|
const nanoid = eval(`require("nanoid")`);
|
|
const tokens = $.read(TOKENS_KEY) || [];
|
|
// const now = Date.now();
|
|
// for (const key in tokens) {
|
|
// const token = tokens[key];
|
|
// if (token.exp != null || token.exp < now) {
|
|
// delete tokens[key];
|
|
// }
|
|
// }
|
|
if (!token) {
|
|
do {
|
|
token = nanoid.customAlphabet(nanoid.urlAlphabet)();
|
|
} while (tokens.find((t) => t.token === token));
|
|
}
|
|
tokens.push({
|
|
...payload,
|
|
token,
|
|
createdAt: Date.now(),
|
|
expiresIn: expiresIn > 0 ? options?.expiresIn : undefined,
|
|
exp: expiresIn > 0 ? Date.now() + expiresIn : undefined,
|
|
});
|
|
|
|
$.write(tokens, TOKENS_KEY);
|
|
return success(res, {
|
|
token,
|
|
// secret,
|
|
});
|
|
} catch (e) {
|
|
return failed(
|
|
res,
|
|
new InternalServerError(
|
|
'TOKEN_SIGN_FAILED',
|
|
`Failed to sign token`,
|
|
`Reason: ${e.message ?? e}`,
|
|
),
|
|
);
|
|
}
|
|
}
|