@ruiapp/rapid-core 0.9.2 → 0.9.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.
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, UpdateEntityByIdOptions } from "../types";
1
+ import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, RpdRouteActionConfig, UpdateEntityByIdOptions } from "../types";
2
2
  import { IRpdServer, RapidPlugin } from "./server";
3
3
  import { RouteContext } from "./routeContext";
4
4
  import { ActionHandlerContext } from "./actionHandler";
@@ -38,6 +38,8 @@ declare class PluginManager {
38
38
  onPrepareRouteContext(routeContext: RouteContext): Promise<void>;
39
39
  /** 在接收到HTTP请求,执行 actions 前调用。 */
40
40
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
41
+ /** 在执行 action hanlder 前调用。 */
42
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
41
43
  /** 在创建实体前调用。 */
42
44
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
43
45
  /** 在更新实体前调用。 */
@@ -2,7 +2,7 @@ import { RapidRequest } from "./request";
2
2
  import { RapidResponse } from "./response";
3
3
  import { HttpStatus } from "./http-types";
4
4
  import { IRpdServer } from "./server";
5
- import { IDatabaseAccessor, IDatabaseClient } from "../types";
5
+ import { IDatabaseAccessor, IDatabaseClient, RpdRoute } from "../types";
6
6
  export type Next = () => Promise<void>;
7
7
  export type TransactionState = "uninited" | "inited" | "started";
8
8
  export declare class RouteContext {
@@ -14,7 +14,7 @@ export declare class RouteContext {
14
14
  method: string;
15
15
  path: string;
16
16
  params: Record<string, string>;
17
- routeConfig: any;
17
+ routeConfig: RpdRoute;
18
18
  static newSystemOperationContext(server: IRpdServer): RouteContext;
19
19
  constructor(server: IRpdServer, request?: RapidRequest);
20
20
  clone(): RouteContext;
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseClient, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
1
+ import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseClient, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdRouteActionConfig, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
2
2
  import { IPluginActionHandler, ActionHandler, ActionHandlerContext } from "./actionHandler";
3
3
  import { Next, RouteContext } from "./routeContext";
4
4
  import EntityManager from "../dataAccess/entityManager";
@@ -32,6 +32,7 @@ export interface IRpdServer {
32
32
  emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): void;
33
33
  handleRequest(request: RapidRequest, next: Next): Promise<Response>;
34
34
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
35
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
35
36
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
36
37
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
37
38
  registerCronJob(job: CronJobConfiguration): void;
@@ -108,6 +109,8 @@ export interface RapidPlugin {
108
109
  onPrepareRouteContext?: (server: IRpdServer, routeContext: RouteContext) => Promise<any>;
109
110
  /** 在接收到HTTP请求,执行 actions 前调用。 */
110
111
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
112
+ /** 在执行 action hanlder 前调用。 */
113
+ beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
111
114
  /** 在创建实体前调用。 */
112
115
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
113
116
  /** 在更新实体前调用。 */
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export * from "./utilities/accessControlUtility";
15
15
  export * from "./utilities/entityUtility";
16
16
  export * from "./utilities/jwtUtility";
17
17
  export * from "./utilities/timeUtility";
18
+ export * from "./utilities/passwordUtility";
18
19
  export * from "./helpers/entityHelpers";
19
20
  export * from "./helpers/licenseHelper";
20
21
  export * from "./deno-std/http/cookie";
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ var qs = require('qs');
9
9
  var dayjs = require('dayjs');
10
10
  var jsonwebtoken = require('jsonwebtoken');
11
11
  var crypto = require('crypto');
12
- var bcrypt = require('bcrypt');
12
+ var bcrypt = require('bcryptjs');
13
13
  var path = require('path');
14
14
  var fs = require('fs');
15
15
  var uuid = require('uuid');
@@ -928,6 +928,14 @@ class PluginManager {
928
928
  }
929
929
  }
930
930
  }
931
+ /** 在执行 action hanlder 前调用。 */
932
+ async beforeRunActionHandler(handlerContext, actionConfig) {
933
+ for (const plugin of this.#plugins) {
934
+ if (plugin.beforeRunActionHandler) {
935
+ await plugin.beforeRunActionHandler(this.#server, handlerContext, actionConfig);
936
+ }
937
+ }
938
+ }
931
939
  /** 在创建实体前调用。 */
932
940
  async beforeCreateEntity(model, options) {
933
941
  for (const plugin of this.#plugins) {
@@ -1030,6 +1038,7 @@ async function buildRoutes(server, applicationConfig) {
1030
1038
  if (!handler) {
1031
1039
  throw new Error("Unknown handler: " + actionCode);
1032
1040
  }
1041
+ await server.beforeRunActionHandler(handlerContext, actionConfig);
1033
1042
  const result = handler(handlerContext, actionConfig.config);
1034
1043
  if (result instanceof Promise) {
1035
1044
  await result;
@@ -4301,6 +4310,9 @@ class RapidServer {
4301
4310
  async beforeRunRouteActions(handlerContext) {
4302
4311
  await this.#pluginManager.beforeRunRouteActions(handlerContext);
4303
4312
  }
4313
+ async beforeRunActionHandler(handlerContext, actionConfig) {
4314
+ await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
4315
+ }
4304
4316
  async beforeCreateEntity(model, options) {
4305
4317
  await this.#pluginManager.beforeCreateEntity(model, options);
4306
4318
  }
@@ -5015,6 +5027,30 @@ async function generateJwtSecretKey() {
5015
5027
  return encode(exportedKey);
5016
5028
  }
5017
5029
 
5030
+ /**
5031
+ * Generates password hash.
5032
+ * @param password
5033
+ * @param salt
5034
+ * @returns
5035
+ */
5036
+ async function generatePasswordHash(password, salt) {
5037
+ if (!salt) {
5038
+ salt = 10;
5039
+ }
5040
+ const passwordHash = await bcrypt__default["default"].hash(password, salt);
5041
+ return passwordHash;
5042
+ }
5043
+ /**
5044
+ * Validates the password against the hash.
5045
+ * @param password
5046
+ * @param passwordHash
5047
+ * @returns
5048
+ */
5049
+ async function validatePassword(password, passwordHash) {
5050
+ const isMatch = await bcrypt__default["default"].compare(password, passwordHash);
5051
+ return isMatch;
5052
+ }
5053
+
5018
5054
  function validateLicense(server) {
5019
5055
  const licenseService = server.getService("licenseService");
5020
5056
  const license = licenseService.getLicense();
@@ -6010,66 +6046,66 @@ var queryDatabase = /*#__PURE__*/Object.freeze({
6010
6046
  * This plugin provide:
6011
6047
  * - routes for manage data in database.
6012
6048
  */
6013
- const routeConfigs = [
6049
+ const entityOperationConfigs = [
6014
6050
  {
6015
- code: "createBatch",
6016
- method: "POST",
6017
- endpoint: "/operations/create_batch",
6018
- handlerCode: "createCollectionEntitiesBatch",
6051
+ operationCode: "createBatch",
6052
+ httpMethod: "POST",
6053
+ requestEndpoint: "/operations/create_batch",
6054
+ actionHandlerCode: "createCollectionEntitiesBatch",
6019
6055
  },
6020
6056
  {
6021
- code: "find",
6022
- method: "POST",
6023
- endpoint: "/operations/find",
6024
- handlerCode: "findCollectionEntities",
6057
+ operationCode: "find",
6058
+ httpMethod: "POST",
6059
+ requestEndpoint: "/operations/find",
6060
+ actionHandlerCode: "findCollectionEntities",
6025
6061
  },
6026
6062
  {
6027
- code: "count",
6028
- method: "POST",
6029
- endpoint: "/operations/count",
6030
- handlerCode: "countCollectionEntities",
6063
+ operationCode: "count",
6064
+ httpMethod: "POST",
6065
+ requestEndpoint: "/operations/count",
6066
+ actionHandlerCode: "countCollectionEntities",
6031
6067
  },
6032
6068
  {
6033
- code: "delete",
6034
- method: "POST",
6035
- endpoint: "/operations/delete",
6036
- handlerCode: "deleteCollectionEntities",
6069
+ operationCode: "delete",
6070
+ httpMethod: "POST",
6071
+ requestEndpoint: "/operations/delete",
6072
+ actionHandlerCode: "deleteCollectionEntities",
6037
6073
  },
6038
6074
  {
6039
- code: "addRelations",
6040
- method: "POST",
6041
- endpoint: "/operations/add_relations",
6042
- handlerCode: "addEntityRelations",
6075
+ operationCode: "addRelations",
6076
+ httpMethod: "POST",
6077
+ requestEndpoint: "/operations/add_relations",
6078
+ actionHandlerCode: "addEntityRelations",
6043
6079
  },
6044
6080
  {
6045
- code: "removeRelations",
6046
- method: "POST",
6047
- endpoint: "/operations/remove_relations",
6048
- handlerCode: "removeEntityRelations",
6081
+ operationCode: "removeRelations",
6082
+ httpMethod: "POST",
6083
+ requestEndpoint: "/operations/remove_relations",
6084
+ actionHandlerCode: "removeEntityRelations",
6049
6085
  },
6050
6086
  {
6051
- code: "getById",
6052
- method: "GET",
6053
- endpoint: "/:id",
6054
- handlerCode: "findCollectionEntityById",
6087
+ operationCode: "getById",
6088
+ httpMethod: "GET",
6089
+ requestEndpoint: "/:id",
6090
+ actionHandlerCode: "findCollectionEntityById",
6055
6091
  },
6056
6092
  {
6057
- code: "create",
6058
- method: "POST",
6059
- endpoint: "",
6060
- handlerCode: "createCollectionEntity",
6093
+ operationCode: "create",
6094
+ httpMethod: "POST",
6095
+ requestEndpoint: "",
6096
+ actionHandlerCode: "createCollectionEntity",
6061
6097
  },
6062
6098
  {
6063
- code: "updateById",
6064
- method: "PATCH",
6065
- endpoint: "/:id",
6066
- handlerCode: "updateCollectionEntityById",
6099
+ operationCode: "updateById",
6100
+ httpMethod: "PATCH",
6101
+ requestEndpoint: "/:id",
6102
+ actionHandlerCode: "updateCollectionEntityById",
6067
6103
  },
6068
6104
  {
6069
- code: "deleteById",
6070
- method: "DELETE",
6071
- endpoint: "/:id",
6072
- handlerCode: "deleteCollectionEntityById",
6105
+ operationCode: "deleteById",
6106
+ httpMethod: "DELETE",
6107
+ requestEndpoint: "/:id",
6108
+ actionHandlerCode: "deleteCollectionEntityById",
6073
6109
  },
6074
6110
  ];
6075
6111
  class DataManager {
@@ -6106,17 +6142,17 @@ class DataManager {
6106
6142
  const routes = [];
6107
6143
  models.forEach((model) => {
6108
6144
  const { namespace, singularCode, pluralCode } = model;
6109
- routeConfigs.forEach((routeConfig) => {
6145
+ entityOperationConfigs.forEach((entityOperationConfig) => {
6110
6146
  routes.push({
6111
6147
  namespace,
6112
- name: `${namespace}.${singularCode}.${routeConfig.code}`,
6113
- code: `${namespace}.${singularCode}.${routeConfig.code}`,
6148
+ name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
6149
+ code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
6114
6150
  type: "RESTful",
6115
- method: routeConfig.method,
6116
- endpoint: `/${namespace}/${pluralCode}${routeConfig.endpoint}`,
6151
+ method: entityOperationConfig.httpMethod,
6152
+ endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
6117
6153
  actions: [
6118
6154
  {
6119
- code: routeConfig.handlerCode,
6155
+ code: entityOperationConfig.actionHandlerCode,
6120
6156
  config: {
6121
6157
  namespace,
6122
6158
  singularCode,
@@ -6892,12 +6928,11 @@ async function handler$e(plugin, ctx, options) {
6892
6928
  if (!user) {
6893
6929
  throw new Error("User not found.");
6894
6930
  }
6895
- const isMatch = await bcrypt__default["default"].compare(oldPassword, user.password);
6931
+ const isMatch = await validatePassword(oldPassword, user.password);
6896
6932
  if (!isMatch) {
6897
6933
  throw new Error("旧密码错误。");
6898
6934
  }
6899
- const saltRounds = 10;
6900
- const passwordHash = await bcrypt__default["default"].hash(newPassword, saltRounds);
6935
+ const passwordHash = await generatePasswordHash(newPassword);
6901
6936
  await userDataAccessor.updateById(user.id, {
6902
6937
  password: passwordHash,
6903
6938
  }, routeContext?.getDbTransactionClient());
@@ -6939,7 +6974,7 @@ async function handler$d(plugin, ctx, options) {
6939
6974
  if (user.state !== "enabled") {
6940
6975
  throw new Error("用户已被禁用,不允许登录。");
6941
6976
  }
6942
- const isMatch = await bcrypt__default["default"].compare(password, user.password);
6977
+ const isMatch = await validatePassword(password, user.password);
6943
6978
  if (!isMatch) {
6944
6979
  throw new Error("用户名或密码错误。");
6945
6980
  }
@@ -7040,8 +7075,7 @@ async function handler$a(plugin, ctx, options) {
7040
7075
  if (!user) {
7041
7076
  throw new Error("User not found.");
7042
7077
  }
7043
- const saltRounds = 10;
7044
- const passwordHash = await bcrypt__default["default"].hash(password, saltRounds);
7078
+ const passwordHash = await generatePasswordHash(password);
7045
7079
  await userDataAccessor.updateById(user.id, {
7046
7080
  password: passwordHash,
7047
7081
  }, routeContext?.getDbTransactionClient());
@@ -9570,6 +9604,7 @@ exports.deleteCookie = deleteCookie;
9570
9604
  exports.detectChangedFieldsOfEntity = detectChangedFieldsOfEntity;
9571
9605
  exports.formatDateTimeWithTimezone = formatDateTimeWithTimezone;
9572
9606
  exports.generateJwtSecretKey = generateJwtSecretKey;
9607
+ exports.generatePasswordHash = generatePasswordHash;
9573
9608
  exports.getCookies = getCookies;
9574
9609
  exports.getDateString = getDateString;
9575
9610
  exports.getEntityRelationTargetId = getEntityRelationTargetId;
@@ -9581,4 +9616,5 @@ exports.mapDbRowToEntity = mapDbRowToEntity;
9581
9616
  exports.setCookie = setCookie;
9582
9617
  exports.tryValidateLicense = tryValidateLicense;
9583
9618
  exports.validateLicense = validateLicense;
9619
+ exports.validatePassword = validatePassword;
9584
9620
  exports.verifyJwt = verifyJwt;
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions, IDatabaseClient } from "./types";
1
+ import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions, IDatabaseClient, RpdRouteActionConfig } from "./types";
2
2
  import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
3
3
  import { IRpdServer, RapidPlugin } from "./core/server";
4
4
  import { Next } from "./core/routeContext";
@@ -58,6 +58,7 @@ export declare class RapidServer implements IRpdServer {
58
58
  get middlewares(): any[];
59
59
  handleRequest(rapidRequest: RapidRequest, next: Next): Promise<Response>;
60
60
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
61
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
61
62
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
62
63
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
63
64
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Generates password hash.
3
+ * @param password
4
+ * @param salt
5
+ * @returns
6
+ */
7
+ export declare function generatePasswordHash(password: string, salt?: number | string): Promise<string>;
8
+ /**
9
+ * Validates the password against the hash.
10
+ * @param password
11
+ * @param passwordHash
12
+ * @returns
13
+ */
14
+ export declare function validatePassword(password: string, passwordHash: string): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "typescript": "^4.8.4"
20
20
  },
21
21
  "dependencies": {
22
- "bcrypt": "^5.1.1",
22
+ "bcryptjs": "^3.0.2",
23
23
  "cron": "^3.1.7",
24
24
  "dayjs": "^1.11.7",
25
25
  "jsonwebtoken": "^9.0.2",
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, UpdateEntityByIdOptions } from "~/types";
1
+ import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, RpdRouteActionConfig, UpdateEntityByIdOptions } from "~/types";
2
2
  import { IRpdServer, RapidPlugin } from "./server";
3
3
  import { RouteContext } from "./routeContext";
4
4
  import { ActionHandlerContext } from "./actionHandler";
@@ -162,6 +162,15 @@ class PluginManager {
162
162
  }
163
163
  }
164
164
 
165
+ /** 在执行 action hanlder 前调用。 */
166
+ async beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) {
167
+ for (const plugin of this.#plugins) {
168
+ if (plugin.beforeRunActionHandler) {
169
+ await plugin.beforeRunActionHandler(this.#server, handlerContext, actionConfig);
170
+ }
171
+ }
172
+ }
173
+
165
174
  /** 在创建实体前调用。 */
166
175
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
167
176
  for (const plugin of this.#plugins) {
@@ -2,7 +2,7 @@ import { RapidRequest } from "./request";
2
2
  import { RapidResponse } from "./response";
3
3
  import { HttpStatus } from "./http-types";
4
4
  import { IRpdServer } from "./server";
5
- import { IDatabaseAccessor, IDatabaseClient } from "~/types";
5
+ import { IDatabaseAccessor, IDatabaseClient, RpdRoute } from "~/types";
6
6
 
7
7
  export type Next = () => Promise<void>;
8
8
 
@@ -18,7 +18,7 @@ export class RouteContext {
18
18
  method: string;
19
19
  path: string;
20
20
  params: Record<string, string>;
21
- routeConfig: any;
21
+ routeConfig: RpdRoute;
22
22
  #server: IRpdServer;
23
23
  #dbTransactionClient: IDatabaseClient | undefined;
24
24
  #dbTransactionState: TransactionState;
@@ -74,6 +74,8 @@ export async function buildRoutes(server: IRpdServer, applicationConfig: RpdAppl
74
74
  throw new Error("Unknown handler: " + actionCode);
75
75
  }
76
76
 
77
+ await server.beforeRunActionHandler(handlerContext, actionConfig);
78
+
77
79
  const result = handler(handlerContext, actionConfig.config);
78
80
  if (result instanceof Promise) {
79
81
  await result;
@@ -13,6 +13,7 @@ import {
13
13
  RpdApplicationConfig,
14
14
  RpdDataModel,
15
15
  RpdDataModelProperty,
16
+ RpdRouteActionConfig,
16
17
  RpdServerEventTypes,
17
18
  UpdateEntityByIdOptions,
18
19
  } from "~/types";
@@ -53,6 +54,7 @@ export interface IRpdServer {
53
54
  emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): void;
54
55
  handleRequest(request: RapidRequest, next: Next): Promise<Response>;
55
56
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
57
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
56
58
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
57
59
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
58
60
 
@@ -145,6 +147,8 @@ export interface RapidPlugin {
145
147
  onPrepareRouteContext?: (server: IRpdServer, routeContext: RouteContext) => Promise<any>;
146
148
  /** 在接收到HTTP请求,执行 actions 前调用。 */
147
149
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
150
+ /** 在执行 action hanlder 前调用。 */
151
+ beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
148
152
  /** 在创建实体前调用。 */
149
153
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
150
154
  /** 在更新实体前调用。 */
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ export * from "./utilities/accessControlUtility";
22
22
  export * from "./utilities/entityUtility";
23
23
  export * from "./utilities/jwtUtility";
24
24
  export * from "./utilities/timeUtility";
25
+ export * from "./utilities/passwordUtility";
25
26
 
26
27
  export * from "./helpers/entityHelpers";
27
28
  export * from "./helpers/licenseHelper";
@@ -1,7 +1,6 @@
1
- import bcrypt from "bcrypt";
2
1
  import { ActionHandlerContext } from "~/core/actionHandler";
3
- import { RapidPlugin } from "~/core/server";
4
2
  import AuthPlugin from "../AuthPlugin";
3
+ import { generatePasswordHash, validatePassword } from "~/utilities/passwordUtility";
5
4
 
6
5
  export const code = "changePassword";
7
6
 
@@ -43,13 +42,12 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
43
42
  throw new Error("User not found.");
44
43
  }
45
44
 
46
- const isMatch = await bcrypt.compare(oldPassword, user.password);
45
+ const isMatch = await validatePassword(oldPassword, user.password);
47
46
  if (!isMatch) {
48
47
  throw new Error("旧密码错误。");
49
48
  }
50
49
 
51
- const saltRounds = 10;
52
- const passwordHash = await bcrypt.hash(newPassword, saltRounds);
50
+ const passwordHash = await generatePasswordHash(newPassword);
53
51
 
54
52
  await userDataAccessor.updateById(
55
53
  user.id,
@@ -1,10 +1,9 @@
1
- import bcrypt from "bcrypt";
2
1
  import { setCookie } from "~/deno-std/http/cookie";
3
2
  import { ActionHandlerContext } from "~/core/actionHandler";
4
- import { RapidPlugin } from "~/core/server";
5
3
  import AuthService from "../services/AuthService";
6
4
  import { validateLicense } from "~/helpers/licenseHelper";
7
5
  import AuthPlugin from "../AuthPlugin";
6
+ import { validatePassword } from "~/utilities/passwordUtility";
8
7
 
9
8
  export const code = "createSession";
10
9
 
@@ -45,7 +44,7 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
45
44
  throw new Error("用户已被禁用,不允许登录。");
46
45
  }
47
46
 
48
- const isMatch = await bcrypt.compare(password, user.password);
47
+ const isMatch = await validatePassword(password, user.password);
49
48
  if (!isMatch) {
50
49
  throw new Error("用户名或密码错误。");
51
50
  }
@@ -1,7 +1,6 @@
1
- import bcrypt from "bcrypt";
2
1
  import { ActionHandlerContext } from "~/core/actionHandler";
3
- import { RapidPlugin } from "~/core/server";
4
2
  import AuthPlugin from "../AuthPlugin";
3
+ import { generatePasswordHash } from "~/utilities/passwordUtility";
5
4
 
6
5
  export const code = "resetPassword";
7
6
 
@@ -32,8 +31,7 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
32
31
  throw new Error("User not found.");
33
32
  }
34
33
 
35
- const saltRounds = 10;
36
- const passwordHash = await bcrypt.hash(password, saltRounds);
34
+ const passwordHash = await generatePasswordHash(password);
37
35
 
38
36
  await userDataAccessor.updateById(
39
37
  user.id,
@@ -25,71 +25,71 @@ import {
25
25
  RapidPlugin,
26
26
  } from "~/core/server";
27
27
 
28
- const routeConfigs: {
29
- code: string;
30
- method: RpdHttpMethod;
31
- endpoint: string;
32
- handlerCode: string;
28
+ const entityOperationConfigs: {
29
+ operationCode: string;
30
+ httpMethod: RpdHttpMethod;
31
+ requestEndpoint: string;
32
+ actionHandlerCode: string;
33
33
  }[] = [
34
34
  {
35
- code: "createBatch",
36
- method: "POST",
37
- endpoint: "/operations/create_batch",
38
- handlerCode: "createCollectionEntitiesBatch",
35
+ operationCode: "createBatch",
36
+ httpMethod: "POST",
37
+ requestEndpoint: "/operations/create_batch",
38
+ actionHandlerCode: "createCollectionEntitiesBatch",
39
39
  },
40
40
  {
41
- code: "find",
42
- method: "POST",
43
- endpoint: "/operations/find",
44
- handlerCode: "findCollectionEntities",
41
+ operationCode: "find",
42
+ httpMethod: "POST",
43
+ requestEndpoint: "/operations/find",
44
+ actionHandlerCode: "findCollectionEntities",
45
45
  },
46
46
  {
47
- code: "count",
48
- method: "POST",
49
- endpoint: "/operations/count",
50
- handlerCode: "countCollectionEntities",
47
+ operationCode: "count",
48
+ httpMethod: "POST",
49
+ requestEndpoint: "/operations/count",
50
+ actionHandlerCode: "countCollectionEntities",
51
51
  },
52
52
  {
53
- code: "delete",
54
- method: "POST",
55
- endpoint: "/operations/delete",
56
- handlerCode: "deleteCollectionEntities",
53
+ operationCode: "delete",
54
+ httpMethod: "POST",
55
+ requestEndpoint: "/operations/delete",
56
+ actionHandlerCode: "deleteCollectionEntities",
57
57
  },
58
58
  {
59
- code: "addRelations",
60
- method: "POST",
61
- endpoint: "/operations/add_relations",
62
- handlerCode: "addEntityRelations",
59
+ operationCode: "addRelations",
60
+ httpMethod: "POST",
61
+ requestEndpoint: "/operations/add_relations",
62
+ actionHandlerCode: "addEntityRelations",
63
63
  },
64
64
  {
65
- code: "removeRelations",
66
- method: "POST",
67
- endpoint: "/operations/remove_relations",
68
- handlerCode: "removeEntityRelations",
65
+ operationCode: "removeRelations",
66
+ httpMethod: "POST",
67
+ requestEndpoint: "/operations/remove_relations",
68
+ actionHandlerCode: "removeEntityRelations",
69
69
  },
70
70
  {
71
- code: "getById",
72
- method: "GET",
73
- endpoint: "/:id",
74
- handlerCode: "findCollectionEntityById",
71
+ operationCode: "getById",
72
+ httpMethod: "GET",
73
+ requestEndpoint: "/:id",
74
+ actionHandlerCode: "findCollectionEntityById",
75
75
  },
76
76
  {
77
- code: "create",
78
- method: "POST",
79
- endpoint: "",
80
- handlerCode: "createCollectionEntity",
77
+ operationCode: "create",
78
+ httpMethod: "POST",
79
+ requestEndpoint: "",
80
+ actionHandlerCode: "createCollectionEntity",
81
81
  },
82
82
  {
83
- code: "updateById",
84
- method: "PATCH",
85
- endpoint: "/:id",
86
- handlerCode: "updateCollectionEntityById",
83
+ operationCode: "updateById",
84
+ httpMethod: "PATCH",
85
+ requestEndpoint: "/:id",
86
+ actionHandlerCode: "updateCollectionEntityById",
87
87
  },
88
88
  {
89
- code: "deleteById",
90
- method: "DELETE",
91
- endpoint: "/:id",
92
- handlerCode: "deleteCollectionEntityById",
89
+ operationCode: "deleteById",
90
+ httpMethod: "DELETE",
91
+ requestEndpoint: "/:id",
92
+ actionHandlerCode: "deleteCollectionEntityById",
93
93
  },
94
94
  ];
95
95
 
@@ -135,17 +135,17 @@ class DataManager implements RapidPlugin {
135
135
  models.forEach((model) => {
136
136
  const { namespace, singularCode, pluralCode } = model;
137
137
 
138
- routeConfigs.forEach((routeConfig) => {
138
+ entityOperationConfigs.forEach((entityOperationConfig) => {
139
139
  routes.push({
140
140
  namespace,
141
- name: `${namespace}.${singularCode}.${routeConfig.code}`,
142
- code: `${namespace}.${singularCode}.${routeConfig.code}`,
141
+ name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
142
+ code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
143
143
  type: "RESTful",
144
- method: routeConfig.method,
145
- endpoint: `/${namespace}/${pluralCode}${routeConfig.endpoint}`,
144
+ method: entityOperationConfig.httpMethod,
145
+ endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
146
146
  actions: [
147
147
  {
148
- code: routeConfig.handlerCode,
148
+ code: entityOperationConfig.actionHandlerCode,
149
149
  config: {
150
150
  namespace,
151
151
  singularCode,
package/src/server.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  RpdEntityCreateEventPayload,
19
19
  EmitServerEventOptions,
20
20
  IDatabaseClient,
21
+ RpdRouteActionConfig,
21
22
  } from "./types";
22
23
 
23
24
  import QueryBuilder from "./queryBuilder/queryBuilder";
@@ -475,6 +476,10 @@ export class RapidServer implements IRpdServer {
475
476
  await this.#pluginManager.beforeRunRouteActions(handlerContext);
476
477
  }
477
478
 
479
+ async beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) {
480
+ await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
481
+ }
482
+
478
483
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
479
484
  await this.#pluginManager.beforeCreateEntity(model, options);
480
485
  }
@@ -0,0 +1,26 @@
1
+ import bcrypt from "bcryptjs";
2
+
3
+ /**
4
+ * Generates password hash.
5
+ * @param password
6
+ * @param salt
7
+ * @returns
8
+ */
9
+ export async function generatePasswordHash(password: string, salt?: number | string): Promise<string> {
10
+ if (!salt) {
11
+ salt = 10;
12
+ }
13
+ const passwordHash = await bcrypt.hash(password, salt);
14
+ return passwordHash;
15
+ }
16
+
17
+ /**
18
+ * Validates the password against the hash.
19
+ * @param password
20
+ * @param passwordHash
21
+ * @returns
22
+ */
23
+ export async function validatePassword(password: string, passwordHash: string): Promise<boolean> {
24
+ const isMatch = await bcrypt.compare(password, passwordHash);
25
+ return isMatch;
26
+ }