@ruiapp/rapid-core 0.9.2 → 0.9.4
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/dist/core/pluginManager.d.ts +3 -1
- package/dist/core/routeContext.d.ts +2 -2
- package/dist/core/server.d.ts +4 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +118 -54
- package/dist/server.d.ts +2 -1
- package/dist/utilities/passwordUtility.d.ts +14 -0
- package/package.json +2 -2
- package/src/core/pluginManager.ts +10 -1
- package/src/core/routeContext.ts +2 -2
- package/src/core/routesBuilder.ts +2 -0
- package/src/core/server.ts +4 -0
- package/src/dataAccess/entityManager.ts +1 -1
- package/src/index.ts +5 -1
- package/src/plugins/auth/actionHandlers/changePassword.ts +3 -5
- package/src/plugins/auth/actionHandlers/createSession.ts +2 -3
- package/src/plugins/auth/actionHandlers/resetPassword.ts +2 -4
- package/src/plugins/dataManage/DataManagePlugin.ts +51 -51
- package/src/server.ts +5 -0
- package/src/utilities/passwordUtility.ts +26 -0
- /package/dist/helpers/{entityHelpers.d.ts → entityHelper.d.ts} +0 -0
- /package/src/helpers/{entityHelpers.ts → entityHelper.ts} +0 -0
|
@@ -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:
|
|
17
|
+
routeConfig: RpdRoute;
|
|
18
18
|
static newSystemOperationContext(server: IRpdServer): RouteContext;
|
|
19
19
|
constructor(server: IRpdServer, request?: RapidRequest);
|
|
20
20
|
clone(): RouteContext;
|
package/dist/core/server.d.ts
CHANGED
|
@@ -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,8 +15,12 @@ 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 "./
|
|
18
|
+
export * from "./utilities/passwordUtility";
|
|
19
|
+
export * from "./helpers/entityHelper";
|
|
19
20
|
export * from "./helpers/licenseHelper";
|
|
21
|
+
export * as entityHelper from "./helpers/entityHelper";
|
|
22
|
+
export * as licenseHelper from "./helpers/licenseHelper";
|
|
23
|
+
export * as metaHelper from "./helpers/metaHelper";
|
|
20
24
|
export * from "./deno-std/http/cookie";
|
|
21
25
|
export { mapDbRowToEntity } from "./dataAccess/entityMapper";
|
|
22
26
|
export * as bootstrapApplicationConfig from "./bootstrapApplicationConfig";
|
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('
|
|
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;
|
|
@@ -2079,6 +2088,20 @@ function getEntityPropertyByFieldName(server, model, fieldName) {
|
|
|
2079
2088
|
return property;
|
|
2080
2089
|
}
|
|
2081
2090
|
|
|
2091
|
+
var metaHelper = /*#__PURE__*/Object.freeze({
|
|
2092
|
+
__proto__: null,
|
|
2093
|
+
isRelationProperty: isRelationProperty,
|
|
2094
|
+
isOneRelationProperty: isOneRelationProperty,
|
|
2095
|
+
isManyRelationProperty: isManyRelationProperty,
|
|
2096
|
+
getEntityProperties: getEntityProperties,
|
|
2097
|
+
getEntityPropertiesIncludingBase: getEntityPropertiesIncludingBase,
|
|
2098
|
+
getEntityPropertyByCode: getEntityPropertyByCode,
|
|
2099
|
+
getEntityProperty: getEntityProperty,
|
|
2100
|
+
getEntityOwnPropertyByCode: getEntityOwnPropertyByCode,
|
|
2101
|
+
getEntityOwnProperty: getEntityOwnProperty,
|
|
2102
|
+
getEntityPropertyByFieldName: getEntityPropertyByFieldName
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2082
2105
|
function getNowString() {
|
|
2083
2106
|
return dayjs__default["default"]().format("YYYY-MM-DD HH:mm:ss.SSS");
|
|
2084
2107
|
}
|
|
@@ -2279,6 +2302,11 @@ function detectChangedFieldsOfEntity(server, model, before, after) {
|
|
|
2279
2302
|
return null;
|
|
2280
2303
|
}
|
|
2281
2304
|
|
|
2305
|
+
var entityHelper = /*#__PURE__*/Object.freeze({
|
|
2306
|
+
__proto__: null,
|
|
2307
|
+
detectChangedFieldsOfEntity: detectChangedFieldsOfEntity
|
|
2308
|
+
});
|
|
2309
|
+
|
|
2282
2310
|
async function validateEntity(server, model, entity) {
|
|
2283
2311
|
for (const propCode in entity) {
|
|
2284
2312
|
let prop = getEntityPropertyByCode(server, model, propCode);
|
|
@@ -4301,6 +4329,9 @@ class RapidServer {
|
|
|
4301
4329
|
async beforeRunRouteActions(handlerContext) {
|
|
4302
4330
|
await this.#pluginManager.beforeRunRouteActions(handlerContext);
|
|
4303
4331
|
}
|
|
4332
|
+
async beforeRunActionHandler(handlerContext, actionConfig) {
|
|
4333
|
+
await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
|
|
4334
|
+
}
|
|
4304
4335
|
async beforeCreateEntity(model, options) {
|
|
4305
4336
|
await this.#pluginManager.beforeCreateEntity(model, options);
|
|
4306
4337
|
}
|
|
@@ -5015,6 +5046,30 @@ async function generateJwtSecretKey() {
|
|
|
5015
5046
|
return encode(exportedKey);
|
|
5016
5047
|
}
|
|
5017
5048
|
|
|
5049
|
+
/**
|
|
5050
|
+
* Generates password hash.
|
|
5051
|
+
* @param password
|
|
5052
|
+
* @param salt
|
|
5053
|
+
* @returns
|
|
5054
|
+
*/
|
|
5055
|
+
async function generatePasswordHash(password, salt) {
|
|
5056
|
+
if (!salt) {
|
|
5057
|
+
salt = 10;
|
|
5058
|
+
}
|
|
5059
|
+
const passwordHash = await bcrypt__default["default"].hash(password, salt);
|
|
5060
|
+
return passwordHash;
|
|
5061
|
+
}
|
|
5062
|
+
/**
|
|
5063
|
+
* Validates the password against the hash.
|
|
5064
|
+
* @param password
|
|
5065
|
+
* @param passwordHash
|
|
5066
|
+
* @returns
|
|
5067
|
+
*/
|
|
5068
|
+
async function validatePassword(password, passwordHash) {
|
|
5069
|
+
const isMatch = await bcrypt__default["default"].compare(password, passwordHash);
|
|
5070
|
+
return isMatch;
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5018
5073
|
function validateLicense(server) {
|
|
5019
5074
|
const licenseService = server.getService("licenseService");
|
|
5020
5075
|
const license = licenseService.getLicense();
|
|
@@ -5039,6 +5094,12 @@ function tryValidateLicense(logger, server) {
|
|
|
5039
5094
|
return false;
|
|
5040
5095
|
}
|
|
5041
5096
|
|
|
5097
|
+
var licenseHelper = /*#__PURE__*/Object.freeze({
|
|
5098
|
+
__proto__: null,
|
|
5099
|
+
validateLicense: validateLicense,
|
|
5100
|
+
tryValidateLicense: tryValidateLicense
|
|
5101
|
+
});
|
|
5102
|
+
|
|
5042
5103
|
const values = new Map();
|
|
5043
5104
|
async function set(key, value, options) {
|
|
5044
5105
|
let expireAt = -1;
|
|
@@ -6010,66 +6071,66 @@ var queryDatabase = /*#__PURE__*/Object.freeze({
|
|
|
6010
6071
|
* This plugin provide:
|
|
6011
6072
|
* - routes for manage data in database.
|
|
6012
6073
|
*/
|
|
6013
|
-
const
|
|
6074
|
+
const entityOperationConfigs = [
|
|
6014
6075
|
{
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6076
|
+
operationCode: "createBatch",
|
|
6077
|
+
httpMethod: "POST",
|
|
6078
|
+
requestEndpoint: "/operations/create_batch",
|
|
6079
|
+
actionHandlerCode: "createCollectionEntitiesBatch",
|
|
6019
6080
|
},
|
|
6020
6081
|
{
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6082
|
+
operationCode: "find",
|
|
6083
|
+
httpMethod: "POST",
|
|
6084
|
+
requestEndpoint: "/operations/find",
|
|
6085
|
+
actionHandlerCode: "findCollectionEntities",
|
|
6025
6086
|
},
|
|
6026
6087
|
{
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6088
|
+
operationCode: "count",
|
|
6089
|
+
httpMethod: "POST",
|
|
6090
|
+
requestEndpoint: "/operations/count",
|
|
6091
|
+
actionHandlerCode: "countCollectionEntities",
|
|
6031
6092
|
},
|
|
6032
6093
|
{
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6094
|
+
operationCode: "delete",
|
|
6095
|
+
httpMethod: "POST",
|
|
6096
|
+
requestEndpoint: "/operations/delete",
|
|
6097
|
+
actionHandlerCode: "deleteCollectionEntities",
|
|
6037
6098
|
},
|
|
6038
6099
|
{
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6100
|
+
operationCode: "addRelations",
|
|
6101
|
+
httpMethod: "POST",
|
|
6102
|
+
requestEndpoint: "/operations/add_relations",
|
|
6103
|
+
actionHandlerCode: "addEntityRelations",
|
|
6043
6104
|
},
|
|
6044
6105
|
{
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6106
|
+
operationCode: "removeRelations",
|
|
6107
|
+
httpMethod: "POST",
|
|
6108
|
+
requestEndpoint: "/operations/remove_relations",
|
|
6109
|
+
actionHandlerCode: "removeEntityRelations",
|
|
6049
6110
|
},
|
|
6050
6111
|
{
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6112
|
+
operationCode: "getById",
|
|
6113
|
+
httpMethod: "GET",
|
|
6114
|
+
requestEndpoint: "/:id",
|
|
6115
|
+
actionHandlerCode: "findCollectionEntityById",
|
|
6055
6116
|
},
|
|
6056
6117
|
{
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6118
|
+
operationCode: "create",
|
|
6119
|
+
httpMethod: "POST",
|
|
6120
|
+
requestEndpoint: "",
|
|
6121
|
+
actionHandlerCode: "createCollectionEntity",
|
|
6061
6122
|
},
|
|
6062
6123
|
{
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6124
|
+
operationCode: "updateById",
|
|
6125
|
+
httpMethod: "PATCH",
|
|
6126
|
+
requestEndpoint: "/:id",
|
|
6127
|
+
actionHandlerCode: "updateCollectionEntityById",
|
|
6067
6128
|
},
|
|
6068
6129
|
{
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6130
|
+
operationCode: "deleteById",
|
|
6131
|
+
httpMethod: "DELETE",
|
|
6132
|
+
requestEndpoint: "/:id",
|
|
6133
|
+
actionHandlerCode: "deleteCollectionEntityById",
|
|
6073
6134
|
},
|
|
6074
6135
|
];
|
|
6075
6136
|
class DataManager {
|
|
@@ -6106,17 +6167,17 @@ class DataManager {
|
|
|
6106
6167
|
const routes = [];
|
|
6107
6168
|
models.forEach((model) => {
|
|
6108
6169
|
const { namespace, singularCode, pluralCode } = model;
|
|
6109
|
-
|
|
6170
|
+
entityOperationConfigs.forEach((entityOperationConfig) => {
|
|
6110
6171
|
routes.push({
|
|
6111
6172
|
namespace,
|
|
6112
|
-
name: `${namespace}.${singularCode}.${
|
|
6113
|
-
code: `${namespace}.${singularCode}.${
|
|
6173
|
+
name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
6174
|
+
code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
6114
6175
|
type: "RESTful",
|
|
6115
|
-
method:
|
|
6116
|
-
endpoint: `/${namespace}/${pluralCode}${
|
|
6176
|
+
method: entityOperationConfig.httpMethod,
|
|
6177
|
+
endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
|
|
6117
6178
|
actions: [
|
|
6118
6179
|
{
|
|
6119
|
-
code:
|
|
6180
|
+
code: entityOperationConfig.actionHandlerCode,
|
|
6120
6181
|
config: {
|
|
6121
6182
|
namespace,
|
|
6122
6183
|
singularCode,
|
|
@@ -6892,12 +6953,11 @@ async function handler$e(plugin, ctx, options) {
|
|
|
6892
6953
|
if (!user) {
|
|
6893
6954
|
throw new Error("User not found.");
|
|
6894
6955
|
}
|
|
6895
|
-
const isMatch = await
|
|
6956
|
+
const isMatch = await validatePassword(oldPassword, user.password);
|
|
6896
6957
|
if (!isMatch) {
|
|
6897
6958
|
throw new Error("旧密码错误。");
|
|
6898
6959
|
}
|
|
6899
|
-
const
|
|
6900
|
-
const passwordHash = await bcrypt__default["default"].hash(newPassword, saltRounds);
|
|
6960
|
+
const passwordHash = await generatePasswordHash(newPassword);
|
|
6901
6961
|
await userDataAccessor.updateById(user.id, {
|
|
6902
6962
|
password: passwordHash,
|
|
6903
6963
|
}, routeContext?.getDbTransactionClient());
|
|
@@ -6939,7 +6999,7 @@ async function handler$d(plugin, ctx, options) {
|
|
|
6939
6999
|
if (user.state !== "enabled") {
|
|
6940
7000
|
throw new Error("用户已被禁用,不允许登录。");
|
|
6941
7001
|
}
|
|
6942
|
-
const isMatch = await
|
|
7002
|
+
const isMatch = await validatePassword(password, user.password);
|
|
6943
7003
|
if (!isMatch) {
|
|
6944
7004
|
throw new Error("用户名或密码错误。");
|
|
6945
7005
|
}
|
|
@@ -7040,8 +7100,7 @@ async function handler$a(plugin, ctx, options) {
|
|
|
7040
7100
|
if (!user) {
|
|
7041
7101
|
throw new Error("User not found.");
|
|
7042
7102
|
}
|
|
7043
|
-
const
|
|
7044
|
-
const passwordHash = await bcrypt__default["default"].hash(password, saltRounds);
|
|
7103
|
+
const passwordHash = await generatePasswordHash(password);
|
|
7045
7104
|
await userDataAccessor.updateById(user.id, {
|
|
7046
7105
|
password: passwordHash,
|
|
7047
7106
|
}, routeContext?.getDbTransactionClient());
|
|
@@ -9568,8 +9627,10 @@ exports.createJwt = createJwt;
|
|
|
9568
9627
|
exports.decodeJwt = decodeJwt;
|
|
9569
9628
|
exports.deleteCookie = deleteCookie;
|
|
9570
9629
|
exports.detectChangedFieldsOfEntity = detectChangedFieldsOfEntity;
|
|
9630
|
+
exports.entityHelper = entityHelper;
|
|
9571
9631
|
exports.formatDateTimeWithTimezone = formatDateTimeWithTimezone;
|
|
9572
9632
|
exports.generateJwtSecretKey = generateJwtSecretKey;
|
|
9633
|
+
exports.generatePasswordHash = generatePasswordHash;
|
|
9573
9634
|
exports.getCookies = getCookies;
|
|
9574
9635
|
exports.getDateString = getDateString;
|
|
9575
9636
|
exports.getEntityRelationTargetId = getEntityRelationTargetId;
|
|
@@ -9577,8 +9638,11 @@ exports.getNowString = getNowString;
|
|
|
9577
9638
|
exports.getNowStringWithTimezone = getNowStringWithTimezone;
|
|
9578
9639
|
exports.getSetCookies = getSetCookies;
|
|
9579
9640
|
exports.isAccessAllowed = isAccessAllowed;
|
|
9641
|
+
exports.licenseHelper = licenseHelper;
|
|
9580
9642
|
exports.mapDbRowToEntity = mapDbRowToEntity;
|
|
9643
|
+
exports.metaHelper = metaHelper;
|
|
9581
9644
|
exports.setCookie = setCookie;
|
|
9582
9645
|
exports.tryValidateLicense = tryValidateLicense;
|
|
9583
9646
|
exports.validateLicense = validateLicense;
|
|
9647
|
+
exports.validatePassword = validatePassword;
|
|
9584
9648
|
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.
|
|
3
|
+
"version": "0.9.4",
|
|
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
|
-
"
|
|
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) {
|
package/src/core/routeContext.ts
CHANGED
|
@@ -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:
|
|
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;
|
package/src/core/server.ts
CHANGED
|
@@ -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
|
/** 在更新实体前调用。 */
|
|
@@ -23,7 +23,7 @@ import { isNullOrUndefined } from "~/utilities/typeUtility";
|
|
|
23
23
|
import { mapDbRowToEntity, mapEntityToDbRow } from "./entityMapper";
|
|
24
24
|
import { mapPropertyNameToColumnName } from "./propertyMapper";
|
|
25
25
|
import { IRpdServer, RapidPlugin } from "~/core/server";
|
|
26
|
-
import { detectChangedFieldsOfEntity } from "~/helpers/
|
|
26
|
+
import { detectChangedFieldsOfEntity } from "~/helpers/entityHelper";
|
|
27
27
|
import {
|
|
28
28
|
cloneDeep,
|
|
29
29
|
concat,
|
package/src/index.ts
CHANGED
|
@@ -22,9 +22,13 @@ 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
|
-
export * from "./helpers/
|
|
27
|
+
export * from "./helpers/entityHelper";
|
|
27
28
|
export * from "./helpers/licenseHelper";
|
|
29
|
+
export * as entityHelper from "./helpers/entityHelper";
|
|
30
|
+
export * as licenseHelper from "./helpers/licenseHelper";
|
|
31
|
+
export * as metaHelper from "./helpers/metaHelper";
|
|
28
32
|
|
|
29
33
|
export * from "./deno-std/http/cookie";
|
|
30
34
|
|
|
@@ -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
|
|
45
|
+
const isMatch = await validatePassword(oldPassword, user.password);
|
|
47
46
|
if (!isMatch) {
|
|
48
47
|
throw new Error("旧密码错误。");
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
const
|
|
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
|
|
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
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const entityOperationConfigs: {
|
|
29
|
+
operationCode: string;
|
|
30
|
+
httpMethod: RpdHttpMethod;
|
|
31
|
+
requestEndpoint: string;
|
|
32
|
+
actionHandlerCode: string;
|
|
33
33
|
}[] = [
|
|
34
34
|
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
operationCode: "createBatch",
|
|
36
|
+
httpMethod: "POST",
|
|
37
|
+
requestEndpoint: "/operations/create_batch",
|
|
38
|
+
actionHandlerCode: "createCollectionEntitiesBatch",
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
operationCode: "find",
|
|
42
|
+
httpMethod: "POST",
|
|
43
|
+
requestEndpoint: "/operations/find",
|
|
44
|
+
actionHandlerCode: "findCollectionEntities",
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
operationCode: "count",
|
|
48
|
+
httpMethod: "POST",
|
|
49
|
+
requestEndpoint: "/operations/count",
|
|
50
|
+
actionHandlerCode: "countCollectionEntities",
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
operationCode: "delete",
|
|
54
|
+
httpMethod: "POST",
|
|
55
|
+
requestEndpoint: "/operations/delete",
|
|
56
|
+
actionHandlerCode: "deleteCollectionEntities",
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
operationCode: "addRelations",
|
|
60
|
+
httpMethod: "POST",
|
|
61
|
+
requestEndpoint: "/operations/add_relations",
|
|
62
|
+
actionHandlerCode: "addEntityRelations",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
operationCode: "removeRelations",
|
|
66
|
+
httpMethod: "POST",
|
|
67
|
+
requestEndpoint: "/operations/remove_relations",
|
|
68
|
+
actionHandlerCode: "removeEntityRelations",
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
operationCode: "getById",
|
|
72
|
+
httpMethod: "GET",
|
|
73
|
+
requestEndpoint: "/:id",
|
|
74
|
+
actionHandlerCode: "findCollectionEntityById",
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
operationCode: "create",
|
|
78
|
+
httpMethod: "POST",
|
|
79
|
+
requestEndpoint: "",
|
|
80
|
+
actionHandlerCode: "createCollectionEntity",
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
operationCode: "updateById",
|
|
84
|
+
httpMethod: "PATCH",
|
|
85
|
+
requestEndpoint: "/:id",
|
|
86
|
+
actionHandlerCode: "updateCollectionEntityById",
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
138
|
+
entityOperationConfigs.forEach((entityOperationConfig) => {
|
|
139
139
|
routes.push({
|
|
140
140
|
namespace,
|
|
141
|
-
name: `${namespace}.${singularCode}.${
|
|
142
|
-
code: `${namespace}.${singularCode}.${
|
|
141
|
+
name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
142
|
+
code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
143
143
|
type: "RESTful",
|
|
144
|
-
method:
|
|
145
|
-
endpoint: `/${namespace}/${pluralCode}${
|
|
144
|
+
method: entityOperationConfig.httpMethod,
|
|
145
|
+
endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
|
|
146
146
|
actions: [
|
|
147
147
|
{
|
|
148
|
-
code:
|
|
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
|
+
}
|
|
File without changes
|
|
File without changes
|