@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 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
@@ -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
  }
@@ -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
- const { id: userId } = authenticatePayload;
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
- where: {
54
- userId
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: item.id,
63
- appId: item.id,
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 { id: userId } = authenticatePayload;
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 { id: userId } = authenticatePayload;
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-signature",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "description": "用于实现一个签名和验证算法",
5
5
  "main": "index.js",
6
6
  "scripts": {