@chevre/domain 23.2.0-alpha.40 → 23.2.0-alpha.42
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/example/src/chevre/offerCatalog/upsertOfferCatalogItemsByIdentifier.ts +4 -1
- package/example/src/chevre/offerCatalog/upsertOfferCatalogsByIdentifier.ts +4 -1
- package/example/src/chevre/{upsertOffersByIdentifier.ts → offers/upsertOffersByIdentifier.ts} +5 -3
- package/example/src/chevre/orderNumber/decryptOrderNumber.ts +14 -0
- package/example/src/chevre/transactionNumber/publishByTimestamp.ts +34 -0
- package/example/src/chevre/transactionNumber/testRandomness.ts +42 -0
- package/lib/chevre/repo/aggregateOffer.d.ts +6 -1
- package/lib/chevre/repo/aggregateOffer.js +11 -3
- package/lib/chevre/repo/confirmationNumber.js +1 -1
- package/lib/chevre/repo/mongoose/schemas/setting.d.ts +11 -0
- package/lib/chevre/repo/mongoose/schemas/setting.js +1 -0
- package/lib/chevre/repo/offerCatalog.d.ts +4 -0
- package/lib/chevre/repo/offerCatalog.js +9 -3
- package/lib/chevre/repo/offerCatalogItem.d.ts +4 -0
- package/lib/chevre/repo/offerCatalogItem.js +9 -3
- package/lib/chevre/repo/orderNumber.js +1 -1
- package/lib/chevre/repo/serviceOutputIdentifier.js +1 -1
- package/lib/chevre/repo/transactionNumber.d.ts +6 -0
- package/lib/chevre/repo/transactionNumber.js +70 -22
- package/package.json +3 -2
package/example/src/chevre/{upsertOffersByIdentifier.ts → offers/upsertOffersByIdentifier.ts}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// tslint:disable:no-console
|
|
2
2
|
import * as mongoose from 'mongoose';
|
|
3
3
|
|
|
4
|
-
import { chevre } from '
|
|
4
|
+
import { chevre } from '../../../../lib/index';
|
|
5
5
|
|
|
6
6
|
const PROJECT_ID = String(process.env.PROJECT_ID);
|
|
7
7
|
const PRICE = 1234;
|
|
@@ -49,8 +49,10 @@ async function main() {
|
|
|
49
49
|
project: { typeOf: chevre.factory.organizationType.Project, id: PROJECT_ID },
|
|
50
50
|
typeOf: chevre.factory.offerType.Offer
|
|
51
51
|
}
|
|
52
|
-
]
|
|
53
|
-
|
|
52
|
+
],
|
|
53
|
+
{
|
|
54
|
+
productType: chevre.factory.product.ProductType.EventService
|
|
55
|
+
}
|
|
54
56
|
);
|
|
55
57
|
// tslint:disable-next-line:no-null-keyword
|
|
56
58
|
console.dir(result, { depth: null });
|
|
@@ -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,34 @@
|
|
|
1
|
+
// tslint:disable:no-console
|
|
2
|
+
import * as mongoose from 'mongoose';
|
|
3
|
+
import * as fpe2Module from 'node-fpe-v2';
|
|
4
|
+
|
|
5
|
+
const fpe2 = (fpe2Module as unknown) as typeof fpe2Module.default;
|
|
6
|
+
|
|
7
|
+
import { chevre } from '../../../../lib/index';
|
|
8
|
+
|
|
9
|
+
// tslint:disable-next-line:max-func-body-length
|
|
10
|
+
async function main() {
|
|
11
|
+
await mongoose.connect(<string>process.env.MONGOLAB_URI, { autoIndex: false });
|
|
12
|
+
|
|
13
|
+
const transactionNumberRepo = await chevre.repository.TransactionNumber.createInstance({
|
|
14
|
+
connection: mongoose.connection
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const result = await transactionNumberRepo.publishByTimestamp({ startDate: new Date() });
|
|
18
|
+
console.log(result);
|
|
19
|
+
console.log('length:', result.transactionNumber.length);
|
|
20
|
+
|
|
21
|
+
const decryptResult = fpe2({ secret: String(result.secret) })
|
|
22
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
23
|
+
.decrypt(result.transactionNumber.slice(2));
|
|
24
|
+
console.log(decryptResult);
|
|
25
|
+
console.log(decryptResult === `${result.timestamp}${result.incrReply.toString()
|
|
26
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
27
|
+
.padStart(2, '0')}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
main()
|
|
31
|
+
.then(() => {
|
|
32
|
+
console.log('success!');
|
|
33
|
+
})
|
|
34
|
+
.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();
|
|
@@ -74,7 +74,12 @@ export declare class AggregateOfferRepo {
|
|
|
74
74
|
/**
|
|
75
75
|
* コードをキーにして冪等置換(2023-12-13~)
|
|
76
76
|
*/
|
|
77
|
-
upsertByIdentifier(params: Omit<factory.unitPriceOffer.IUnitPriceOffer, 'id'>[]
|
|
77
|
+
upsertByIdentifier(params: Omit<factory.unitPriceOffer.IUnitPriceOffer, 'id'>[], options: {
|
|
78
|
+
/**
|
|
79
|
+
* プロダクトタイプでfilter(2026-01-30~)
|
|
80
|
+
*/
|
|
81
|
+
productType: factory.product.ProductType;
|
|
82
|
+
}): Promise<{
|
|
78
83
|
bulkWriteResult: BulkWriteResult;
|
|
79
84
|
modifiedOffers: {
|
|
80
85
|
id: string;
|
|
@@ -648,22 +648,30 @@ class AggregateOfferRepo {
|
|
|
648
648
|
/**
|
|
649
649
|
* コードをキーにして冪等置換(2023-12-13~)
|
|
650
650
|
*/
|
|
651
|
-
upsertByIdentifier(params) {
|
|
651
|
+
upsertByIdentifier(params, options) {
|
|
652
652
|
return __awaiter(this, void 0, void 0, function* () {
|
|
653
|
+
const { productType } = options;
|
|
653
654
|
const uniqid = yield Promise.resolve().then(() => require('uniqid'));
|
|
654
655
|
const insertBulkWriteOps = [];
|
|
655
656
|
// const updateBulkWriteOps: AnyBulkWriteOperation<factory.aggregateOffer.IAggregateOffer>[] = [];
|
|
656
657
|
const queryFilters = [];
|
|
657
658
|
if (Array.isArray(params)) {
|
|
658
659
|
params.forEach((p) => {
|
|
660
|
+
var _a;
|
|
661
|
+
// 指定されたproductTypeを強制する
|
|
662
|
+
if (((_a = p.itemOffered) === null || _a === void 0 ? void 0 : _a.typeOf) !== productType) {
|
|
663
|
+
throw new factory.errors.Argument('itemOffered.typeOf', `not matched with productType: ${productType}`);
|
|
664
|
+
}
|
|
659
665
|
// リソースのユニークネスを保証するfilter
|
|
660
666
|
const filter = {
|
|
661
667
|
'project.id': { $eq: p.project.id },
|
|
662
|
-
'offers.identifier': { $exists: true, $eq: p.identifier }
|
|
668
|
+
'offers.identifier': { $exists: true, $eq: p.identifier },
|
|
669
|
+
'offers.itemOffered.typeOf': { $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
663
670
|
};
|
|
664
671
|
queryFilters.push({
|
|
665
672
|
'project.id': { $eq: p.project.id },
|
|
666
|
-
'offers.identifier': { $exists: true, $eq: p.identifier }
|
|
673
|
+
'offers.identifier': { $exists: true, $eq: p.identifier },
|
|
674
|
+
'offers.itemOffered.typeOf': { $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
667
675
|
});
|
|
668
676
|
const newOfferId = uniqid(); // setOnInsert時のみに利用する新ID
|
|
669
677
|
// サブオファー最適化(2023-12-22~)
|
|
@@ -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");
|
|
@@ -110,6 +110,16 @@ export interface IJWTSetting {
|
|
|
110
110
|
*/
|
|
111
111
|
algorithm: Algorithm;
|
|
112
112
|
}
|
|
113
|
+
export interface ITransactionNumberSetting {
|
|
114
|
+
/**
|
|
115
|
+
* fpe暗号鍵
|
|
116
|
+
*/
|
|
117
|
+
fpeSecret: string;
|
|
118
|
+
/**
|
|
119
|
+
* "1"
|
|
120
|
+
*/
|
|
121
|
+
version: string;
|
|
122
|
+
}
|
|
113
123
|
export interface ISetting {
|
|
114
124
|
defaultSenderEmail?: string;
|
|
115
125
|
jwt?: IJWTSetting;
|
|
@@ -127,6 +137,7 @@ export interface ISetting {
|
|
|
127
137
|
};
|
|
128
138
|
quota?: IQuotaSettings;
|
|
129
139
|
storage?: IStorageSettings;
|
|
140
|
+
transactionNumber?: ITransactionNumberSetting;
|
|
130
141
|
/**
|
|
131
142
|
* 通知設定
|
|
132
143
|
*/
|
|
@@ -19,6 +19,7 @@ const schemaDefinition = {
|
|
|
19
19
|
onTransactionStatusChanged: mongoose_1.SchemaTypes.Mixed,
|
|
20
20
|
quota: mongoose_1.SchemaTypes.Mixed,
|
|
21
21
|
storage: mongoose_1.SchemaTypes.Mixed,
|
|
22
|
+
transactionNumber: mongoose_1.SchemaTypes.Mixed,
|
|
22
23
|
triggerWebhook: mongoose_1.SchemaTypes.Mixed,
|
|
23
24
|
useInformResourceTypes: [String],
|
|
24
25
|
userPoolIdOld: String,
|
|
@@ -40,6 +40,10 @@ export declare class OfferCatalogRepo {
|
|
|
40
40
|
* support only update(2026-01-30~)
|
|
41
41
|
*/
|
|
42
42
|
update: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* プロダクトタイプでfilter(2026-01-30~)
|
|
45
|
+
*/
|
|
46
|
+
productType: factory.product.ProductType;
|
|
43
47
|
}): Promise<{
|
|
44
48
|
bulkWriteResult: BulkWriteResult;
|
|
45
49
|
modifiedCatalogs: {
|
|
@@ -197,7 +197,7 @@ class OfferCatalogRepo {
|
|
|
197
197
|
*/
|
|
198
198
|
upsertManyByIdentifier(params, options) {
|
|
199
199
|
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
-
const { update } = options;
|
|
200
|
+
const { productType, update } = options;
|
|
201
201
|
const uniqid = yield Promise.resolve().then(() => require('uniqid'));
|
|
202
202
|
const bulkWriteOps = [];
|
|
203
203
|
const queryFilters = [];
|
|
@@ -207,14 +207,20 @@ class OfferCatalogRepo {
|
|
|
207
207
|
if (typeof identifier !== 'string' || identifier.length === 0) {
|
|
208
208
|
throw new factory.errors.ArgumentNull('identifier');
|
|
209
209
|
}
|
|
210
|
+
// 指定されたproductTypeを強制する
|
|
211
|
+
if (setFields.itemOffered.typeOf !== productType) {
|
|
212
|
+
throw new factory.errors.Argument('itemOffered.typeOf', `not matched with productType: ${productType}`);
|
|
213
|
+
}
|
|
210
214
|
// リソースのユニークネスを保証するfilter
|
|
211
215
|
const filter = {
|
|
212
216
|
'project.id': { $eq: project.id },
|
|
213
|
-
identifier: { $eq: identifier }
|
|
217
|
+
identifier: { $eq: identifier },
|
|
218
|
+
'itemOffered.typeOf': { $exists: true, $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
214
219
|
};
|
|
215
220
|
queryFilters.push({
|
|
216
221
|
'project.id': { $eq: project.id },
|
|
217
|
-
identifier: { $eq: identifier }
|
|
222
|
+
identifier: { $eq: identifier },
|
|
223
|
+
'itemOffered.typeOf': { $exists: true, $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
218
224
|
});
|
|
219
225
|
if (update === true) {
|
|
220
226
|
const updateOne = {
|
|
@@ -37,6 +37,10 @@ export declare class OfferCatalogItemRepo {
|
|
|
37
37
|
* support only update(2026-01-30~)
|
|
38
38
|
*/
|
|
39
39
|
update: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* プロダクトタイプでfilter(2026-01-30~)
|
|
42
|
+
*/
|
|
43
|
+
productType: factory.product.ProductType;
|
|
40
44
|
}): Promise<{
|
|
41
45
|
bulkWriteResult: BulkWriteResult;
|
|
42
46
|
modifiedCatalogs: {
|
|
@@ -161,7 +161,7 @@ class OfferCatalogItemRepo {
|
|
|
161
161
|
*/
|
|
162
162
|
upsertManyByIdentifier(params, options) {
|
|
163
163
|
return __awaiter(this, void 0, void 0, function* () {
|
|
164
|
-
const { update } = options;
|
|
164
|
+
const { productType, update } = options;
|
|
165
165
|
const bulkWriteOps = [];
|
|
166
166
|
const queryFilters = [];
|
|
167
167
|
if (Array.isArray(params)) {
|
|
@@ -170,14 +170,20 @@ class OfferCatalogItemRepo {
|
|
|
170
170
|
if (typeof identifier !== 'string' || identifier.length === 0) {
|
|
171
171
|
throw new factory.errors.ArgumentNull('identifier');
|
|
172
172
|
}
|
|
173
|
+
// 指定されたproductTypeを強制する
|
|
174
|
+
if (setFields.itemOffered.typeOf !== productType) {
|
|
175
|
+
throw new factory.errors.Argument('itemOffered.typeOf', `not matched with productType: ${productType}`);
|
|
176
|
+
}
|
|
173
177
|
// リソースのユニークネスを保証するfilter
|
|
174
178
|
const filter = {
|
|
175
179
|
'project.id': { $eq: project.id },
|
|
176
|
-
identifier: { $eq: identifier }
|
|
180
|
+
identifier: { $eq: identifier },
|
|
181
|
+
'itemOffered.typeOf': { $exists: true, $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
177
182
|
};
|
|
178
183
|
queryFilters.push({
|
|
179
184
|
'project.id': { $eq: project.id },
|
|
180
|
-
identifier: { $eq: identifier }
|
|
185
|
+
identifier: { $eq: identifier },
|
|
186
|
+
'itemOffered.typeOf': { $exists: true, $eq: productType } // プロダクトタイプを変更させないためにフィルター追加(2026-01-30~)
|
|
181
187
|
});
|
|
182
188
|
if (update === true) {
|
|
183
189
|
const updateOne = {
|
|
@@ -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");
|
|
@@ -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,16 @@
|
|
|
1
1
|
import type { Connection } from 'mongoose';
|
|
2
2
|
interface IPublishResult {
|
|
3
3
|
transactionNumber: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
incrReply: number;
|
|
6
|
+
secret?: string;
|
|
4
7
|
}
|
|
5
8
|
/**
|
|
6
9
|
* 取引番号リポジトリ
|
|
7
10
|
*/
|
|
8
11
|
export declare class TransactionNumberRepo {
|
|
9
12
|
private readonly counterRepo;
|
|
13
|
+
private readonly settingModel;
|
|
10
14
|
constructor(params: {
|
|
11
15
|
connection: Connection;
|
|
12
16
|
});
|
|
@@ -16,5 +20,7 @@ export declare class TransactionNumberRepo {
|
|
|
16
20
|
publishByTimestamp(params: {
|
|
17
21
|
startDate: Date;
|
|
18
22
|
}): Promise<IPublishResult>;
|
|
23
|
+
decrypt(id: string): Promise<string>;
|
|
24
|
+
private findSetting;
|
|
19
25
|
}
|
|
20
26
|
export {};
|
|
@@ -11,11 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.TransactionNumberRepo = void 0;
|
|
13
13
|
const cdigit = require("cdigit");
|
|
14
|
+
const crypto_1 = require("crypto");
|
|
14
15
|
const moment = require("moment-timezone");
|
|
15
|
-
|
|
16
|
+
const fpe2Module = require("node-fpe-v2");
|
|
17
|
+
// 型定義が新しいtypescriptに適合しないので、強制的に型変更
|
|
18
|
+
const fpe2 = fpe2Module;
|
|
16
19
|
// tslint:disable-next-line:no-require-imports no-var-requires
|
|
17
|
-
const
|
|
18
|
-
|
|
20
|
+
const fpe1 = require('node-fpe-v1');
|
|
21
|
+
const factory = require("../factory");
|
|
22
|
+
const setting_1 = require("./mongoose/schemas/setting");
|
|
19
23
|
const transactionNumber_1 = require("./mongoose/schemas/transactionNumber");
|
|
20
24
|
const transactionNumberCounter_1 = require("./transactionNumberCounter");
|
|
21
25
|
/**
|
|
@@ -23,25 +27,15 @@ const transactionNumberCounter_1 = require("./transactionNumberCounter");
|
|
|
23
27
|
*/
|
|
24
28
|
class TransactionNumberRepo {
|
|
25
29
|
constructor(params) {
|
|
26
|
-
// const { connection } = params;
|
|
27
|
-
// this.settingModel = connection.model(settingModelName, createSettingSchema());
|
|
28
30
|
this.counterRepo = new transactionNumberCounter_1.TransactionNumberCounterRepo(params);
|
|
31
|
+
this.settingModel = params.connection.model(setting_1.modelName, (0, setting_1.createSchema)());
|
|
29
32
|
}
|
|
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
33
|
/**
|
|
41
34
|
* タイムスタンプから発行する
|
|
42
35
|
*/
|
|
43
36
|
publishByTimestamp(params) {
|
|
44
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
const { fpeSecret, version } = yield this.findSetting();
|
|
45
39
|
const timestamp = moment(params.startDate)
|
|
46
40
|
.valueOf()
|
|
47
41
|
.toString();
|
|
@@ -57,13 +51,67 @@ class TransactionNumberRepo {
|
|
|
57
51
|
includedInDataCatalog: { identifier: transactionNumber_1.DataCatalogIdentifier.transactionNumber },
|
|
58
52
|
expires: dataFeedExpires
|
|
59
53
|
});
|
|
60
|
-
let transactionNumber
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
let transactionNumber;
|
|
55
|
+
let secret;
|
|
56
|
+
if (typeof fpeSecret === 'string' && typeof version === 'string') {
|
|
57
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
58
|
+
const saltDigit = (0, crypto_1.randomInt)(0, 10);
|
|
59
|
+
const saltStr = saltDigit.toString();
|
|
60
|
+
secret = `${fpeSecret}${saltStr}`;
|
|
61
|
+
const cipher = fpe2({ secret });
|
|
62
|
+
// incrReplyが 0〜99 なら "00"〜"99" になり(15桁)
|
|
63
|
+
// incrReplyが 100〜999 なら "100"〜"999" になる(16桁)
|
|
64
|
+
const rawBody = `${timestamp}${incrReply.toString()
|
|
65
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
66
|
+
.padStart(2, '0')}`;
|
|
67
|
+
const encryptedBody = cipher.encrypt(rawBody);
|
|
68
|
+
// ソルトを「あえて」2文字目に含める
|
|
69
|
+
transactionNumber = `${version}${saltStr}${encryptedBody}`;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
transactionNumber = `${timestamp}${incrReply}`;
|
|
73
|
+
// checkdigit
|
|
74
|
+
const cd = cdigit.luhn.compute(transactionNumber);
|
|
75
|
+
transactionNumber = fpe1({ password: cd })
|
|
76
|
+
.encrypt(transactionNumber);
|
|
77
|
+
transactionNumber = `${cd}${transactionNumber}`;
|
|
78
|
+
}
|
|
79
|
+
return { transactionNumber, timestamp, incrReply, secret };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
decrypt(id) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const { fpeSecret } = yield this.findSetting();
|
|
85
|
+
const saltStr = id[1]; // 2文字目からソルト(鍵のヒント)を回収
|
|
86
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
87
|
+
const encryptedBody = id.slice(2);
|
|
88
|
+
const cipher = fpe2({
|
|
89
|
+
secret: `${fpeSecret}${saltStr}`
|
|
90
|
+
});
|
|
91
|
+
return cipher.decrypt(encryptedBody);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
findSetting() {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
const filterQuery = { 'project.id': { $eq: '*' } };
|
|
97
|
+
const projection = {
|
|
98
|
+
_id: 0,
|
|
99
|
+
transactionNumber: 1
|
|
100
|
+
};
|
|
101
|
+
const setting = yield this.settingModel.findOne(filterQuery, projection)
|
|
102
|
+
.lean()
|
|
103
|
+
.exec();
|
|
104
|
+
if (setting === null || setting.transactionNumber === undefined) {
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
const { fpeSecret, version } = setting.transactionNumber;
|
|
108
|
+
if (typeof fpeSecret !== 'string' || fpeSecret === '') {
|
|
109
|
+
throw new factory.errors.NotFound('setting.transactionNumber.secret');
|
|
110
|
+
}
|
|
111
|
+
if (typeof version !== 'string' || version === '') {
|
|
112
|
+
throw new factory.errors.NotFound('setting.transactionNumber.version');
|
|
113
|
+
}
|
|
114
|
+
return { fpeSecret, version };
|
|
67
115
|
});
|
|
68
116
|
}
|
|
69
117
|
}
|
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.
|
|
120
|
+
"version": "23.2.0-alpha.42"
|
|
120
121
|
}
|