-
Notifications
You must be signed in to change notification settings - Fork 668
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
5 changed files
with
192 additions
and
153 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
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,181 @@ | ||
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}`, | ||
), | ||
); | ||
} | ||
} |
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,17 +1,17 @@ | ||
export function findByName(list, name) { | ||
return list.find((item) => item.name === name); | ||
export function findByName(list, name, field = 'name') { | ||
return list.find((item) => item[field] === name); | ||
} | ||
|
||
export function findIndexByName(list, name) { | ||
return list.findIndex((item) => item.name === name); | ||
export function findIndexByName(list, name, field = 'name') { | ||
return list.findIndex((item) => item[field] === name); | ||
} | ||
|
||
export function deleteByName(list, name) { | ||
const idx = findIndexByName(list, name); | ||
export function deleteByName(list, name, field = 'name') { | ||
const idx = findIndexByName(list, name, field); | ||
list.splice(idx, 1); | ||
} | ||
|
||
export function updateByName(list, name, newItem) { | ||
const idx = findIndexByName(list, name); | ||
export function updateByName(list, name, newItem, field = 'name') { | ||
const idx = findIndexByName(list, name, field); | ||
list[idx] = newItem; | ||
} |