@chevre/domain 23.2.0-alpha.41 → 23.2.0-alpha.43

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.
@@ -0,0 +1,14 @@
1
+ // tslint:disable:no-console
2
+ // tslint:disable-next-line:no-require-imports no-var-requires
3
+ const fpe = require('node-fpe-v1');
4
+
5
+ // const orderNumber = 'CIN1-3796505-5174753';
6
+
7
+ const timestamp = '1769837978000';
8
+ const cipher = fpe({ secret: '3:v2-xxxxxx' });
9
+ // .encrypt(orderNumber);
10
+
11
+ const orderNumber = cipher.encrypt(`${timestamp}1`);
12
+ console.log(orderNumber);
13
+ console.log(cipher.decrypt(orderNumber));
14
+ // '1234567'
@@ -0,0 +1,48 @@
1
+ // tslint:disable:object-literal-key-quotes no-console
2
+ import * as mongoose from 'mongoose';
3
+
4
+ import { chevre } from '../../../../lib/index';
5
+
6
+ async function testGeneration() {
7
+ await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
8
+
9
+ const orderNumberRepo = await chevre.repository.OrderNumber.createInstance({
10
+ connection: mongoose.connection
11
+ });
12
+
13
+ const ts = new Date(); // 同一ミリ秒固定
14
+ const results: Record<string, string>[] = [];
15
+
16
+ console.log(`--- 同一ミリ秒(${ts})内での連続生成テスト ---`);
17
+
18
+ // tslint:disable-next-line:no-magic-numbers
19
+ for (let i = 0; i < 100; i += 1) {
20
+ // 同一ミリ秒内でシーケンス(00-99)だけが変わる状況を再現
21
+ const orderNumber = await orderNumberRepo.publishByTimestamp({
22
+ project: { alternateName: 'CIN' },
23
+ orderDate: ts
24
+
25
+ });
26
+
27
+ // 復号して元のデータに戻るかチェック
28
+ const decoded = await orderNumberRepo.decrypt(orderNumber);
29
+ const isSuccess = decoded === `${ts.valueOf()}${(i + 1).toString()
30
+ // tslint:disable-next-line:no-magic-numbers
31
+ .padStart(2, '0')}`;
32
+
33
+ results.push({
34
+ timestamp: ts.valueOf()
35
+ .toString(),
36
+ 'シーケンス': (i + 1).toString(),
37
+ '生成された番号 (17桁)': orderNumber,
38
+ // tslint:disable-next-line:no-magic-numbers
39
+ 'ソルト(2文字目)': orderNumber[2],
40
+ '復号結果': decoded,
41
+ '復号確認': isSuccess ? '✅OK' : '❌NG'
42
+ });
43
+ }
44
+
45
+ console.table(results);
46
+ }
47
+
48
+ testGeneration();
@@ -11,7 +11,7 @@ mongoose.Model.on('index', (...args) => {
11
11
  async function main() {
12
12
  await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
13
13
 
14
- await chevre.repository.EventSeries.createInstance(mongoose.connection);
14
+ await chevre.repository.OfferCatalogItem.createInstance(mongoose.connection);
15
15
  console.log('success!');
16
16
  }
17
17
 
@@ -0,0 +1,23 @@
1
+ // tslint:disable:no-console
2
+ import * as mongoose from 'mongoose';
3
+
4
+ import { chevre } from '../../../../lib/index';
5
+
6
+ // tslint:disable-next-line:max-func-body-length
7
+ async function main() {
8
+ await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
9
+
10
+ const transactionNumberRepo = await chevre.repository.TransactionNumber.createInstance({
11
+ connection: mongoose.connection
12
+ });
13
+
14
+ const result = await transactionNumberRepo.publishByTimestamp({ startDate: new Date() });
15
+ console.log(result);
16
+ console.log('length:', result.transactionNumber.length);
17
+ }
18
+
19
+ main()
20
+ .then(() => {
21
+ console.log('success!');
22
+ })
23
+ .catch(console.error);
@@ -0,0 +1,42 @@
1
+ // tslint:disable:object-literal-key-quotes no-console
2
+ import * as mongoose from 'mongoose';
3
+
4
+ import { chevre } from '../../../../lib/index';
5
+
6
+ async function testGeneration() {
7
+ await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
8
+
9
+ const transactionNumberRepo = await chevre.repository.TransactionNumber.createInstance({
10
+ connection: mongoose.connection
11
+ });
12
+
13
+ const ts = new Date(); // 同一ミリ秒固定
14
+ const results: Record<string, string>[] = [];
15
+
16
+ console.log(`--- 同一ミリ秒(${ts})内での連続生成テスト ---`);
17
+
18
+ // tslint:disable-next-line:no-magic-numbers
19
+ for (let i = 0; i < 100; i += 1) {
20
+ // 同一ミリ秒内でシーケンス(00-99)だけが変わる状況を再現
21
+ const { transactionNumber, timestamp, incrReply } = await transactionNumberRepo.publishByTimestamp({ startDate: ts });
22
+
23
+ // 復号して元のデータに戻るかチェック
24
+ const decoded = await transactionNumberRepo.decrypt(transactionNumber);
25
+ const isSuccess = decoded === `${timestamp}${incrReply.toString()
26
+ // tslint:disable-next-line:no-magic-numbers
27
+ .padStart(2, '0')}`;
28
+
29
+ results.push({
30
+ timestamp: timestamp,
31
+ 'シーケンス': incrReply.toString(),
32
+ '生成された番号 (17桁)': transactionNumber,
33
+ 'ソルト(2文字目)': transactionNumber[1],
34
+ '復号結果': decoded,
35
+ '復号確認': isSuccess ? '✅OK' : '❌NG'
36
+ });
37
+ }
38
+
39
+ console.table(results);
40
+ }
41
+
42
+ testGeneration();
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 取引番号ファクトリー
3
+ */
4
+ export declare class TransactionNumberFactory {
5
+ private readonly fpeSecret;
6
+ private readonly version;
7
+ constructor(params: {
8
+ fpeSecret: string;
9
+ version: string;
10
+ });
11
+ /**
12
+ * 生成: SEQが100を超えると自動で18桁に拡張
13
+ */
14
+ generate(timestamp: string, seq: number): string;
15
+ /**
16
+ * 復号: 17桁でも18桁でも、2文字目以降をまるごとデコード
17
+ */
18
+ decrypt(transactionNumber: string): string;
19
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransactionNumberFactory = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const fpe2Module = require("node-fpe-v2");
6
+ const factory = require("../factory");
7
+ // 型定義が新しいtypescriptに適合しないので、強制的に型変更
8
+ const fpe2 = fpe2Module;
9
+ const TRANSACTION_NUMBER_MIN_LENGTH = 17;
10
+ const SEQUENCE_MAX_LENGTH = 2;
11
+ /**
12
+ * 取引番号ファクトリー
13
+ */
14
+ class TransactionNumberFactory {
15
+ constructor(params) {
16
+ const { fpeSecret, version } = params;
17
+ this.fpeSecret = fpeSecret;
18
+ this.version = version;
19
+ }
20
+ /**
21
+ * 生成: SEQが100を超えると自動で18桁に拡張
22
+ */
23
+ generate(timestamp, seq) {
24
+ // tslint:disable-next-line:no-magic-numbers
25
+ const saltDigit = (0, crypto_1.randomInt)(0, 10);
26
+ const saltStr = saltDigit.toString();
27
+ const cipher = fpe2({ secret: `${this.fpeSecret}${saltStr}` });
28
+ // incrReplyが 0〜99 なら "00"〜"99" になり(15桁)
29
+ // incrReplyが 100〜999 なら "100"〜"999" になる(16桁)
30
+ const zeroPaddingSequence = seq.toString()
31
+ .padStart(SEQUENCE_MAX_LENGTH, '0');
32
+ const rawBody = `${timestamp}${zeroPaddingSequence}`;
33
+ const encryptedBody = cipher.encrypt(rawBody);
34
+ // ソルトを「あえて」2文字目に含める
35
+ const transactionNumber = `${this.version}${saltStr}${encryptedBody}`;
36
+ if (transactionNumber.length < TRANSACTION_NUMBER_MIN_LENGTH) {
37
+ throw new factory.errors.Internal(`transactionNumber length should be >= ${TRANSACTION_NUMBER_MIN_LENGTH}`);
38
+ }
39
+ return transactionNumber;
40
+ }
41
+ /**
42
+ * 復号: 17桁でも18桁でも、2文字目以降をまるごとデコード
43
+ */
44
+ decrypt(transactionNumber) {
45
+ const saltStr = transactionNumber[1]; // 2文字目からソルト(鍵のヒント)を回収
46
+ // tslint:disable-next-line:no-magic-numbers
47
+ const encryptedBody = transactionNumber.slice(2);
48
+ const cipher = fpe2({
49
+ secret: `${this.fpeSecret}${saltStr}`
50
+ });
51
+ return cipher.decrypt(encryptedBody);
52
+ }
53
+ }
54
+ exports.TransactionNumberFactory = TransactionNumberFactory;
@@ -14,7 +14,7 @@ const cdigit = require("cdigit");
14
14
  const moment = require("moment-timezone");
15
15
  // import { RedisClientType } from 'redis';
16
16
  // tslint:disable-next-line:no-require-imports no-var-requires
17
- const fpe = require('node-fpe');
17
+ const fpe = require('node-fpe-v1');
18
18
  // import { createSchema as createSettingSchema, modelName as settingModelName } from './mongoose/schemas/setting';
19
19
  const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
20
20
  const transactionNumberCounter_1 = require("./transactionNumberCounter");
@@ -8,7 +8,7 @@ const settings_1 = require("../../../settings");
8
8
  const modelName = 'OfferCatalog';
9
9
  exports.modelName = modelName;
10
10
  const schemaDefinition = {
11
- project: mongoose_1.SchemaTypes.Mixed,
11
+ project: { type: mongoose_1.SchemaTypes.Mixed, required: true },
12
12
  _id: String,
13
13
  identifier: {
14
14
  type: String,
@@ -22,7 +22,7 @@ const schemaDefinition = {
22
22
  required: true
23
23
  },
24
24
  itemListElement: [mongoose_1.SchemaTypes.Mixed],
25
- itemOffered: mongoose_1.SchemaTypes.Mixed,
25
+ itemOffered: { type: mongoose_1.SchemaTypes.Mixed, required: true },
26
26
  additionalProperty: [mongoose_1.SchemaTypes.Mixed],
27
27
  dateSynced: Date // 追加(2023-09-13~)
28
28
  // createdAt: SchemaTypes.Mixed,
@@ -60,12 +60,6 @@ const indexes = [
60
60
  name: 'searchByIdentifier'
61
61
  }
62
62
  ],
63
- [
64
- { 'project.id': 1, identifier: 1 },
65
- {
66
- name: 'searchByProjectId-v20220721'
67
- }
68
- ],
69
63
  [
70
64
  { 'itemListElement.typeOf': 1, identifier: 1 },
71
65
  {
@@ -8,7 +8,7 @@ const settings_1 = require("../../../settings");
8
8
  const modelName = 'OfferCatalogItem';
9
9
  exports.modelName = modelName;
10
10
  const schemaDefinition = {
11
- project: mongoose_1.SchemaTypes.Mixed,
11
+ project: { type: mongoose_1.SchemaTypes.Mixed, required: true },
12
12
  identifier: {
13
13
  type: String,
14
14
  required: true
@@ -21,7 +21,7 @@ const schemaDefinition = {
21
21
  required: true
22
22
  },
23
23
  itemListElement: [mongoose_1.SchemaTypes.Mixed],
24
- itemOffered: mongoose_1.SchemaTypes.Mixed,
24
+ itemOffered: { type: mongoose_1.SchemaTypes.Mixed, required: true },
25
25
  additionalProperty: [mongoose_1.SchemaTypes.Mixed],
26
26
  dateSynced: Date,
27
27
  relatedOffer: mongoose_1.SchemaTypes.Mixed
@@ -61,6 +61,32 @@ const indexes = [
61
61
  unique: true,
62
62
  name: 'uniqueIdentifier'
63
63
  }
64
+ ],
65
+ [
66
+ { identifier: 1 },
67
+ { name: 'identifier' }
68
+ ],
69
+ [
70
+ { 'itemOffered.typeOf': 1, identifier: 1 },
71
+ { name: 'itemOfferedTypeOf' }
72
+ ],
73
+ [
74
+ { 'itemListElement.typeOf': 1, identifier: 1 },
75
+ {
76
+ name: 'itemListElementTypeOf',
77
+ partialFilterExpression: {
78
+ 'itemListElement.typeOf': { $exists: true }
79
+ }
80
+ }
81
+ ],
82
+ [
83
+ { 'itemListElement.id': 1, identifier: 1 },
84
+ {
85
+ name: 'itemListElementId',
86
+ partialFilterExpression: {
87
+ 'itemListElement.id': { $exists: true }
88
+ }
89
+ }
64
90
  ]
65
91
  ];
66
92
  exports.indexes = indexes;
@@ -110,6 +110,26 @@ export interface IJWTSetting {
110
110
  */
111
111
  algorithm: Algorithm;
112
112
  }
113
+ export interface IOrderNumberSetting {
114
+ /**
115
+ * fpe暗号鍵
116
+ */
117
+ fpeSecret: string;
118
+ /**
119
+ * "1"
120
+ */
121
+ version: string;
122
+ }
123
+ export interface ITransactionNumberSetting {
124
+ /**
125
+ * fpe暗号鍵
126
+ */
127
+ fpeSecret: string;
128
+ /**
129
+ * "1"
130
+ */
131
+ version: string;
132
+ }
113
133
  export interface ISetting {
114
134
  defaultSenderEmail?: string;
115
135
  jwt?: IJWTSetting;
@@ -121,12 +141,14 @@ export interface ISetting {
121
141
  informResource?: factory.project.IInformParams[];
122
142
  };
123
143
  onTransactionStatusChanged?: IOnTransactionStatusChanged;
144
+ orderNumber?: IOrderNumberSetting;
124
145
  project: {
125
146
  id: string;
126
147
  typeOf: factory.organizationType.Project;
127
148
  };
128
149
  quota?: IQuotaSettings;
129
150
  storage?: IStorageSettings;
151
+ transactionNumber?: ITransactionNumberSetting;
130
152
  /**
131
153
  * 通知設定
132
154
  */
@@ -17,8 +17,10 @@ const schemaDefinition = {
17
17
  onTaskStatusChanged: mongoose_1.SchemaTypes.Mixed,
18
18
  onResourceUpdated: mongoose_1.SchemaTypes.Mixed,
19
19
  onTransactionStatusChanged: mongoose_1.SchemaTypes.Mixed,
20
+ orderNumber: mongoose_1.SchemaTypes.Mixed,
20
21
  quota: mongoose_1.SchemaTypes.Mixed,
21
22
  storage: mongoose_1.SchemaTypes.Mixed,
23
+ transactionNumber: mongoose_1.SchemaTypes.Mixed,
22
24
  triggerWebhook: mongoose_1.SchemaTypes.Mixed,
23
25
  useInformResourceTypes: [String],
24
26
  userPoolIdOld: String,
@@ -4,6 +4,7 @@ import type { Connection } from 'mongoose';
4
4
  */
5
5
  export declare class OrderNumberRepo {
6
6
  private readonly counterRepo;
7
+ private readonly settingModel;
7
8
  constructor(params: {
8
9
  connection: Connection;
9
10
  });
@@ -19,4 +20,6 @@ export declare class OrderNumberRepo {
19
20
  */
20
21
  orderDate: Date;
21
22
  }): Promise<string>;
23
+ decrypt(id: string): Promise<string>;
24
+ private findSetting;
22
25
  }
@@ -14,9 +14,12 @@ const cdigit = require("cdigit");
14
14
  const moment = require("moment-timezone");
15
15
  // import { RedisClientType } from 'redis';
16
16
  // tslint:disable-next-line:no-require-imports no-var-requires
17
- const fpe = require('node-fpe');
17
+ const fpe = require('node-fpe-v1');
18
18
  // import { createSchema as createSettingSchema, modelName as settingModelName } from './mongoose/schemas/setting';
19
- const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
19
+ const factory = require("../factory");
20
+ const transactionNumber_1 = require("../factory/transactionNumber");
21
+ const setting_1 = require("./mongoose/schemas/setting");
22
+ const transactionNumber_2 = require("./mongoose/schemas/transactionNumber");
20
23
  const transactionNumberCounter_1 = require("./transactionNumberCounter");
21
24
  const ORDER_NUMBER_SEPARATOR = '-';
22
25
  /**
@@ -27,6 +30,7 @@ class OrderNumberRepo {
27
30
  // const { connection } = params;
28
31
  // this.settingModel = connection.model(settingModelName, createSettingSchema());
29
32
  this.counterRepo = new transactionNumberCounter_1.TransactionNumberCounterRepo(params);
33
+ this.settingModel = params.connection.model(setting_1.modelName, (0, setting_1.createSchema)());
30
34
  }
31
35
  // private static createKey(params: {
32
36
  // orderDate: Date;
@@ -45,6 +49,7 @@ class OrderNumberRepo {
45
49
  */
46
50
  publishByTimestamp(params) {
47
51
  return __awaiter(this, void 0, void 0, function* () {
52
+ const { fpeSecret, version } = yield this.findSetting();
48
53
  const timestamp = moment(params.orderDate)
49
54
  .valueOf()
50
55
  .toString();
@@ -59,25 +64,79 @@ class OrderNumberRepo {
59
64
  .toDate();
60
65
  incrReply = yield this.counterRepo.incrementByMongo({
61
66
  identifier: dataFeedIdentifier,
62
- includedInDataCatalog: { identifier: transactionNumber_1.DataCatalogIdentifier.orderNumber },
67
+ includedInDataCatalog: { identifier: transactionNumber_2.DataCatalogIdentifier.orderNumber },
63
68
  expires: dataFeedExpires
64
69
  });
65
- let orderNumber = `${timestamp}${incrReply}`;
66
- // checkdigit
67
- const cd = cdigit.luhn.compute(orderNumber);
68
- orderNumber = fpe({ password: cd })
69
- .encrypt(orderNumber);
70
- orderNumber = `${projectPrefix}${cd}${orderNumber}`;
71
- orderNumber = `${[
72
- // tslint:disable-next-line:no-magic-numbers
73
- orderNumber.slice(0, 4),
74
- // tslint:disable-next-line:no-magic-numbers
75
- orderNumber.slice(4, 11),
76
- // tslint:disable-next-line:no-magic-numbers
77
- orderNumber.slice(11)
78
- ].join(ORDER_NUMBER_SEPARATOR)}`;
70
+ let orderNumber;
71
+ if (typeof fpeSecret === 'string' && typeof version === 'string') {
72
+ const transactionFactory = new transactionNumber_1.TransactionNumberFactory({ fpeSecret, version });
73
+ orderNumber = transactionFactory.generate(timestamp, incrReply);
74
+ orderNumber = `${projectPrefix.at(0)}${orderNumber}`;
75
+ orderNumber = `${[
76
+ // tslint:disable-next-line:no-magic-numbers
77
+ orderNumber.slice(0, 4),
78
+ // tslint:disable-next-line:no-magic-numbers
79
+ orderNumber.slice(4, 11),
80
+ // tslint:disable-next-line:no-magic-numbers
81
+ orderNumber.slice(11)
82
+ ].join(ORDER_NUMBER_SEPARATOR)}`;
83
+ }
84
+ else {
85
+ orderNumber = `${timestamp}${incrReply}`;
86
+ // checkdigit
87
+ const cd = cdigit.luhn.compute(orderNumber);
88
+ orderNumber = fpe({ password: cd })
89
+ .encrypt(orderNumber);
90
+ orderNumber = `${projectPrefix}${cd}${orderNumber}`;
91
+ orderNumber = `${[
92
+ // tslint:disable-next-line:no-magic-numbers
93
+ orderNumber.slice(0, 4),
94
+ // tslint:disable-next-line:no-magic-numbers
95
+ orderNumber.slice(4, 11),
96
+ // tslint:disable-next-line:no-magic-numbers
97
+ orderNumber.slice(11)
98
+ ].join(ORDER_NUMBER_SEPARATOR)}`;
99
+ }
79
100
  return orderNumber;
80
101
  });
81
102
  }
103
+ decrypt(id) {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ const { fpeSecret, version } = yield this.findSetting();
106
+ if (typeof fpeSecret === 'string' && typeof version === 'string') {
107
+ const transactionFactory = new transactionNumber_1.TransactionNumberFactory({ fpeSecret, version });
108
+ const originalOrderNumber = id.replace(/-/g, '')
109
+ // tslint:disable-next-line:no-magic-numbers
110
+ .slice(1);
111
+ return transactionFactory.decrypt(originalOrderNumber);
112
+ }
113
+ else {
114
+ throw new factory.errors.NotImplemented('no version not implemented');
115
+ }
116
+ });
117
+ }
118
+ findSetting() {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ const filterQuery = { 'project.id': { $eq: '*' } };
121
+ const projection = {
122
+ _id: 0,
123
+ orderNumber: 1
124
+ };
125
+ const setting = yield this.settingModel.findOne(filterQuery, projection)
126
+ .lean()
127
+ .exec();
128
+ if (setting === null || setting.orderNumber === undefined) {
129
+ return {};
130
+ }
131
+ const { fpeSecret, version } = setting.orderNumber;
132
+ if (typeof fpeSecret !== 'string' || fpeSecret === '') {
133
+ throw new factory.errors.NotFound('setting.orderNumber.secret');
134
+ }
135
+ if (typeof version !== 'string' || version === '') {
136
+ throw new factory.errors.NotFound('setting.orderNumber.version');
137
+ }
138
+ return { fpeSecret, version };
139
+ });
140
+ }
82
141
  }
83
142
  exports.OrderNumberRepo = OrderNumberRepo;
@@ -14,7 +14,7 @@ const cdigit = require("cdigit");
14
14
  const moment = require("moment-timezone");
15
15
  // import { RedisClientType } from 'redis';
16
16
  // tslint:disable-next-line:no-require-imports no-var-requires
17
- const fpe = require('node-fpe');
17
+ const fpe = require('node-fpe-v1');
18
18
  // import { createSchema as createSettingSchema, modelName as settingModelName } from './mongoose/schemas/setting';
19
19
  const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
20
20
  const transactionNumberCounter_1 = require("./transactionNumberCounter");
@@ -1,12 +1,15 @@
1
1
  import type { Connection } from 'mongoose';
2
2
  interface IPublishResult {
3
3
  transactionNumber: string;
4
+ timestamp: string;
5
+ incrReply: number;
4
6
  }
5
7
  /**
6
8
  * 取引番号リポジトリ
7
9
  */
8
10
  export declare class TransactionNumberRepo {
9
11
  private readonly counterRepo;
12
+ private readonly settingModel;
10
13
  constructor(params: {
11
14
  connection: Connection;
12
15
  });
@@ -16,5 +19,7 @@ export declare class TransactionNumberRepo {
16
19
  publishByTimestamp(params: {
17
20
  startDate: Date;
18
21
  }): Promise<IPublishResult>;
22
+ decrypt(id: string): Promise<string>;
23
+ private findSetting;
19
24
  }
20
25
  export {};
@@ -12,36 +12,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.TransactionNumberRepo = void 0;
13
13
  const cdigit = require("cdigit");
14
14
  const moment = require("moment-timezone");
15
- // import { RedisClientType } from 'redis';
16
15
  // tslint:disable-next-line:no-require-imports no-var-requires
17
- const fpe = require('node-fpe');
18
- // import { createSchema as createSettingSchema, modelName as settingModelName } from './mongoose/schemas/setting';
19
- const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
16
+ const fpe1 = require('node-fpe-v1');
17
+ const factory = require("../factory");
18
+ const transactionNumber_1 = require("../factory/transactionNumber");
19
+ const setting_1 = require("./mongoose/schemas/setting");
20
+ const transactionNumber_2 = require("./mongoose/schemas/transactionNumber");
20
21
  const transactionNumberCounter_1 = require("./transactionNumberCounter");
21
22
  /**
22
23
  * 取引番号リポジトリ
23
24
  */
24
25
  class TransactionNumberRepo {
25
26
  constructor(params) {
26
- // const { connection } = params;
27
- // this.settingModel = connection.model(settingModelName, createSettingSchema());
28
27
  this.counterRepo = new transactionNumberCounter_1.TransactionNumberCounterRepo(params);
28
+ this.settingModel = params.connection.model(setting_1.modelName, (0, setting_1.createSchema)());
29
29
  }
30
- // private static createKey(params: {
31
- // startDate: Date;
32
- // timestamp: string;
33
- // }): string {
34
- // return util.format(
35
- // '%s:%s',
36
- // TransactionNumberRepo.REDIS_KEY_PREFIX,
37
- // params.timestamp
38
- // );
39
- // }
40
30
  /**
41
31
  * タイムスタンプから発行する
42
32
  */
43
33
  publishByTimestamp(params) {
44
34
  return __awaiter(this, void 0, void 0, function* () {
35
+ const { fpeSecret, version } = yield this.findSetting();
45
36
  const timestamp = moment(params.startDate)
46
37
  .valueOf()
47
38
  .toString();
@@ -54,16 +45,72 @@ class TransactionNumberRepo {
54
45
  .toDate();
55
46
  incrReply = yield this.counterRepo.incrementByMongo({
56
47
  identifier: dataFeedIdentifier,
57
- includedInDataCatalog: { identifier: transactionNumber_1.DataCatalogIdentifier.transactionNumber },
48
+ includedInDataCatalog: { identifier: transactionNumber_2.DataCatalogIdentifier.transactionNumber },
58
49
  expires: dataFeedExpires
59
50
  });
60
- let transactionNumber = `${timestamp}${incrReply}`;
61
- // checkdigit
62
- const cd = cdigit.luhn.compute(transactionNumber);
63
- transactionNumber = fpe({ password: cd })
64
- .encrypt(transactionNumber);
65
- transactionNumber = `${cd}${transactionNumber}`;
66
- return { transactionNumber };
51
+ let transactionNumber;
52
+ // let secret: string | undefined;
53
+ if (typeof fpeSecret === 'string' && typeof version === 'string') {
54
+ const transactionFactory = new transactionNumber_1.TransactionNumberFactory({ fpeSecret, version });
55
+ transactionNumber = transactionFactory.generate(timestamp, incrReply);
56
+ // // tslint:disable-next-line:no-magic-numbers
57
+ // const saltDigit = randomInt(0, 10);
58
+ // const saltStr = saltDigit.toString();
59
+ // secret = `${fpeSecret}${saltStr}`;
60
+ // const cipher = fpe2({ secret });
61
+ // // incrReplyが 0〜99 なら "00"〜"99" になり(15桁)
62
+ // // incrReplyが 100〜999 なら "100"〜"999" になる(16桁)
63
+ // const rawBody = `${timestamp}${incrReply.toString()
64
+ // // tslint:disable-next-line:no-magic-numbers
65
+ // .padStart(2, '0')}`;
66
+ // const encryptedBody = cipher.encrypt(rawBody);
67
+ // // ソルトを「あえて」2文字目に含める
68
+ // transactionNumber = `${version}${saltStr}${encryptedBody}`;
69
+ }
70
+ else {
71
+ transactionNumber = `${timestamp}${incrReply}`;
72
+ // checkdigit
73
+ const cd = cdigit.luhn.compute(transactionNumber);
74
+ transactionNumber = fpe1({ password: cd })
75
+ .encrypt(transactionNumber);
76
+ transactionNumber = `${cd}${transactionNumber}`;
77
+ }
78
+ return { transactionNumber, timestamp, incrReply };
79
+ });
80
+ }
81
+ decrypt(id) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const { fpeSecret, version } = yield this.findSetting();
84
+ if (typeof fpeSecret === 'string' && typeof version === 'string') {
85
+ const transactionFactory = new transactionNumber_1.TransactionNumberFactory({ fpeSecret, version });
86
+ return transactionFactory.decrypt(id);
87
+ }
88
+ else {
89
+ throw new factory.errors.NotImplemented('no version not implemented');
90
+ }
91
+ });
92
+ }
93
+ findSetting() {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ const filterQuery = { 'project.id': { $eq: '*' } };
96
+ const projection = {
97
+ _id: 0,
98
+ transactionNumber: 1
99
+ };
100
+ const setting = yield this.settingModel.findOne(filterQuery, projection)
101
+ .lean()
102
+ .exec();
103
+ if (setting === null || setting.transactionNumber === undefined) {
104
+ return {};
105
+ }
106
+ const { fpeSecret, version } = setting.transactionNumber;
107
+ if (typeof fpeSecret !== 'string' || fpeSecret === '') {
108
+ throw new factory.errors.NotFound('setting.transactionNumber.secret');
109
+ }
110
+ if (typeof version !== 'string' || version === '') {
111
+ throw new factory.errors.NotFound('setting.transactionNumber.version');
112
+ }
113
+ return { fpeSecret, version };
67
114
  });
68
115
  }
69
116
  }
package/package.json CHANGED
@@ -25,7 +25,8 @@
25
25
  "lodash.difference": "^4.5.0",
26
26
  "moment": "^2.29.1",
27
27
  "moment-timezone": "^0.5.33",
28
- "node-fpe": "1.0.0",
28
+ "node-fpe-v1": "npm:node-fpe@1.0.0",
29
+ "node-fpe-v2": "npm:node-fpe@2.0.4",
29
30
  "pug": "^2.0.4",
30
31
  "uniqid": "5.4.0",
31
32
  "uuid": "^3.4.0"
@@ -116,5 +117,5 @@
116
117
  "postversion": "git push origin --tags",
117
118
  "prepublishOnly": "npm run clean && npm run build && npm test && npm run doc"
118
119
  },
119
- "version": "23.2.0-alpha.41"
120
+ "version": "23.2.0-alpha.43"
120
121
  }