@kne/fastify-signature 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/libs/controllers/main.js +9 -0
- package/libs/services/main.js +54 -20
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -34,7 +34,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
34
34
|
},
|
|
35
35
|
getOpenApiParams: request => {
|
|
36
36
|
const { ['x-openapi-appid']: appId, ['x-openapi-timestamp']: timestamp, ['x-openapi-expire']: expire, ['x-openapi-signature']: signature } = request.headers;
|
|
37
|
-
return Object.assign({}, { appId, timestamp, expire, signature }, request.body);
|
|
37
|
+
return Object.assign({}, { appId, timestamp, expire, signature }, request.body?.openApiParams);
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
options
|
package/libs/controllers/main.js
CHANGED
|
@@ -23,6 +23,15 @@ module.exports = fp(async (fastify, options) => {
|
|
|
23
23
|
type: 'number',
|
|
24
24
|
description: '每页数量',
|
|
25
25
|
default: 20
|
|
26
|
+
},
|
|
27
|
+
filter: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
additionalProperties: true,
|
|
30
|
+
properties: {
|
|
31
|
+
keyword: { type: 'string', description: '关键字(AppId/描述/所属用户)' },
|
|
32
|
+
appId: { type: 'string', description: 'AppId' },
|
|
33
|
+
status: { description: '状态: 0开启,1禁用' }
|
|
34
|
+
}
|
|
26
35
|
}
|
|
27
36
|
}
|
|
28
37
|
}
|
package/libs/services/main.js
CHANGED
|
@@ -3,16 +3,27 @@ const crypto = require('crypto');
|
|
|
3
3
|
|
|
4
4
|
module.exports = fp(async (fastify, options) => {
|
|
5
5
|
const { models, services } = fastify[options.name];
|
|
6
|
+
const { Op } = fastify.sequelize.Sequelize;
|
|
7
|
+
|
|
8
|
+
const escapeLike = value => String(value).replace(/[\\%_]/g, '\\$&');
|
|
9
|
+
|
|
10
|
+
const resolveAppId = appId => {
|
|
11
|
+
if (appId == null || appId === '') {
|
|
12
|
+
throw new Error('Invalid appId');
|
|
13
|
+
}
|
|
14
|
+
// 雪花 id 超过 Number.MAX_SAFE_INTEGER,必须始终按字符串查,禁止 Number(appId)
|
|
15
|
+
return String(appId);
|
|
16
|
+
};
|
|
6
17
|
|
|
7
18
|
const create = async (authenticatePayload, { description, userId: targetUserId }) => {
|
|
8
19
|
const { id: userId } = authenticatePayload;
|
|
9
20
|
const secretKey = crypto.randomBytes(options.secretLength).toString('hex');
|
|
10
21
|
const newSecret = await models.secret.create({ secretKey, description, userId: targetUserId || userId });
|
|
11
|
-
return { appId: newSecret.id, secretKey: newSecret.secretKey };
|
|
22
|
+
return { appId: String(newSecret.id), secretKey: newSecret.secretKey };
|
|
12
23
|
};
|
|
13
24
|
|
|
14
25
|
const verify = async ({ appId, timestamp, expire, signature }) => {
|
|
15
|
-
const secret = await models.secret.findByPk(appId);
|
|
26
|
+
const secret = await models.secret.findByPk(resolveAppId(appId));
|
|
16
27
|
if (!secret) {
|
|
17
28
|
throw new Error('Invalid appId');
|
|
18
29
|
}
|
|
@@ -47,21 +58,51 @@ module.exports = fp(async (fastify, options) => {
|
|
|
47
58
|
};
|
|
48
59
|
};
|
|
49
60
|
|
|
50
|
-
const list = async (authenticatePayload, { perPage, currentPage }) => {
|
|
51
|
-
|
|
61
|
+
const list = async (authenticatePayload, { perPage = 20, currentPage = 1, filter }) => {
|
|
62
|
+
filter = Object.assign({}, filter);
|
|
63
|
+
const whereQuery = {};
|
|
64
|
+
const sequelize = fastify.sequelize;
|
|
65
|
+
const castIdLike = value =>
|
|
66
|
+
sequelize.where(sequelize.cast(sequelize.col('secret.id'), 'TEXT'), {
|
|
67
|
+
[Op.iLike]: `%${escapeLike(value)}%`
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const keyword = filter.keyword != null ? String(filter.keyword).trim() : '';
|
|
71
|
+
if (keyword) {
|
|
72
|
+
const like = { [Op.iLike]: `%${escapeLike(keyword)}%` };
|
|
73
|
+
whereQuery[Op.or] = [castIdLike(keyword), { description: like }, { '$user.nickname$': like }, { '$user.email$': like }, { '$user.phone$': like }];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const appId = filter.appId != null ? String(filter.appId).trim() : '';
|
|
77
|
+
if (appId) {
|
|
78
|
+
whereQuery[Op.and] = [...(whereQuery[Op.and] || []), castIdLike(appId)];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (filter.status !== undefined && filter.status !== null && filter.status !== '') {
|
|
82
|
+
whereQuery.status = Number(filter.status);
|
|
83
|
+
}
|
|
84
|
+
|
|
52
85
|
const { count, rows } = await models.secret.findAndCountAll({
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
86
|
+
include: [
|
|
87
|
+
{
|
|
88
|
+
model: options.getUserModel(),
|
|
89
|
+
required: false
|
|
90
|
+
}
|
|
91
|
+
],
|
|
92
|
+
where: whereQuery,
|
|
56
93
|
limit: perPage,
|
|
57
|
-
offset: (currentPage - 1) * perPage
|
|
94
|
+
offset: (currentPage - 1) * perPage,
|
|
95
|
+
order: [['createdAt', 'DESC']],
|
|
96
|
+
distinct: true
|
|
58
97
|
});
|
|
59
98
|
return {
|
|
60
99
|
pageData: rows.map(item => {
|
|
100
|
+
const id = String(item.id);
|
|
61
101
|
return {
|
|
62
|
-
id
|
|
63
|
-
appId:
|
|
102
|
+
id,
|
|
103
|
+
appId: id,
|
|
64
104
|
secretKey: item.secretKey.substring(0, 3) + '*'.repeat(8) + item.secretKey.substring(item.secretKey.length - 3),
|
|
105
|
+
user: item.user,
|
|
65
106
|
description: item.description,
|
|
66
107
|
lastVisitedAt: item.lastVisitedAt,
|
|
67
108
|
status: item.status,
|
|
@@ -73,27 +114,20 @@ module.exports = fp(async (fastify, options) => {
|
|
|
73
114
|
};
|
|
74
115
|
};
|
|
75
116
|
|
|
117
|
+
// list/update/remove 均为 admin 接口,可管理任意用户密钥;勿再按创建者校验归属
|
|
76
118
|
const remove = async (authenticatePayload, { appId }) => {
|
|
77
|
-
const
|
|
78
|
-
const secret = await models.secret.findByPk(appId);
|
|
119
|
+
const secret = await models.secret.findByPk(resolveAppId(appId));
|
|
79
120
|
if (!secret) {
|
|
80
121
|
throw new Error('Invalid appId');
|
|
81
122
|
}
|
|
82
|
-
if (secret.userId !== userId) {
|
|
83
|
-
throw new Error('Invalid appId');
|
|
84
|
-
}
|
|
85
123
|
await secret.destroy();
|
|
86
124
|
};
|
|
87
125
|
|
|
88
126
|
const update = async (authenticatePayload, { appId, status, description }) => {
|
|
89
|
-
const
|
|
90
|
-
const secret = await models.secret.findByPk(appId);
|
|
127
|
+
const secret = await models.secret.findByPk(resolveAppId(appId));
|
|
91
128
|
if (!secret) {
|
|
92
129
|
throw new Error('Invalid appId');
|
|
93
130
|
}
|
|
94
|
-
if (secret.userId !== userId) {
|
|
95
|
-
throw new Error('Invalid appId');
|
|
96
|
-
}
|
|
97
131
|
await secret.update({ status, description });
|
|
98
132
|
};
|
|
99
133
|
|