@labdigital/commercetools-mock 2.0.0 → 2.2.0
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/index.cjs +177 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +177 -26
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/ctMock.ts +49 -29
- package/src/exceptions.ts +4 -0
- package/src/helpers.ts +18 -0
- package/src/lib/password.ts +7 -0
- package/src/oauth/server.ts +137 -3
- package/src/oauth/store.ts +13 -0
- package/src/repositories/customer.ts +30 -8
- package/src/services/my-customer.ts +2 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/ctMock.ts
|
|
2
2
|
import express2 from "express";
|
|
3
|
-
import supertest from "supertest";
|
|
4
3
|
import morgan from "morgan";
|
|
4
|
+
import inject from "light-my-request";
|
|
5
5
|
import { setupServer } from "msw/node";
|
|
6
6
|
import { http, HttpResponse } from "msw";
|
|
7
7
|
|
|
@@ -16,10 +16,12 @@ import assert from "assert";
|
|
|
16
16
|
var CommercetoolsError = class extends Error {
|
|
17
17
|
info;
|
|
18
18
|
statusCode;
|
|
19
|
+
errors;
|
|
19
20
|
constructor(info, statusCode = 400) {
|
|
20
21
|
super(info.message);
|
|
21
22
|
this.info = info;
|
|
22
23
|
this.statusCode = statusCode || 500;
|
|
24
|
+
this.errors = info.errors ?? [];
|
|
23
25
|
}
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -64,6 +66,18 @@ var queryParamsValue = (value) => {
|
|
|
64
66
|
return void 0;
|
|
65
67
|
};
|
|
66
68
|
var cloneObject = (o) => JSON.parse(JSON.stringify(o));
|
|
69
|
+
var mapHeaderType = (outgoingHttpHeaders) => {
|
|
70
|
+
const headersInit = {};
|
|
71
|
+
for (const key in outgoingHttpHeaders) {
|
|
72
|
+
const value = outgoingHttpHeaders[key];
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
headersInit[key] = value.join(", ");
|
|
75
|
+
} else if (value !== void 0) {
|
|
76
|
+
headersInit[key] = value.toString();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return headersInit;
|
|
80
|
+
};
|
|
67
81
|
|
|
68
82
|
// src/lib/expandParser.ts
|
|
69
83
|
var parseExpandClause = (clause) => {
|
|
@@ -1219,6 +1233,16 @@ var OAuth2Store = class {
|
|
|
1219
1233
|
this.tokens.push(token);
|
|
1220
1234
|
return token;
|
|
1221
1235
|
}
|
|
1236
|
+
getCustomerToken(scope, customerId) {
|
|
1237
|
+
const token = {
|
|
1238
|
+
access_token: randomBytes(16).toString("base64"),
|
|
1239
|
+
token_type: "Bearer",
|
|
1240
|
+
expires_in: 172800,
|
|
1241
|
+
scope: scope ? `${scope} custome_id:${customerId}` : `customer_id: ${customerId}`
|
|
1242
|
+
};
|
|
1243
|
+
this.tokens.push(token);
|
|
1244
|
+
return token;
|
|
1245
|
+
}
|
|
1222
1246
|
validateToken(token) {
|
|
1223
1247
|
if (!this.validate)
|
|
1224
1248
|
return true;
|
|
@@ -1240,16 +1264,36 @@ var getBearerToken = (request) => {
|
|
|
1240
1264
|
return void 0;
|
|
1241
1265
|
};
|
|
1242
1266
|
|
|
1267
|
+
// src/lib/password.ts
|
|
1268
|
+
var hashPassword = (clearPassword) => Buffer.from(clearPassword).toString("base64");
|
|
1269
|
+
|
|
1243
1270
|
// src/oauth/server.ts
|
|
1244
1271
|
var OAuth2Server = class {
|
|
1245
1272
|
store;
|
|
1273
|
+
customerRepository;
|
|
1246
1274
|
constructor(options) {
|
|
1247
1275
|
this.store = new OAuth2Store(options.validate);
|
|
1248
1276
|
}
|
|
1277
|
+
setCustomerRepository(repository) {
|
|
1278
|
+
this.customerRepository = repository;
|
|
1279
|
+
}
|
|
1249
1280
|
createRouter() {
|
|
1250
1281
|
const router = express.Router();
|
|
1251
1282
|
router.use(bodyParser.urlencoded({ extended: true }));
|
|
1283
|
+
router.use(this.validateClientCredentials.bind(this));
|
|
1252
1284
|
router.post("/token", this.tokenHandler.bind(this));
|
|
1285
|
+
router.post(
|
|
1286
|
+
"/:projectKey/customers/token",
|
|
1287
|
+
this.customerTokenHandler.bind(this)
|
|
1288
|
+
);
|
|
1289
|
+
router.post(
|
|
1290
|
+
"/:projectKey/in-store/key=:storeKey/customers/token",
|
|
1291
|
+
this.inStoreCustomerTokenHandler.bind(this)
|
|
1292
|
+
);
|
|
1293
|
+
router.post(
|
|
1294
|
+
"/:projectKey/anonymous/token",
|
|
1295
|
+
this.anonymousTokenHandler.bind(this)
|
|
1296
|
+
);
|
|
1253
1297
|
return router;
|
|
1254
1298
|
}
|
|
1255
1299
|
createMiddleware() {
|
|
@@ -1280,7 +1324,7 @@ var OAuth2Server = class {
|
|
|
1280
1324
|
next();
|
|
1281
1325
|
};
|
|
1282
1326
|
}
|
|
1283
|
-
async
|
|
1327
|
+
async validateClientCredentials(request, response, next) {
|
|
1284
1328
|
const authHeader = request.header("Authorization");
|
|
1285
1329
|
if (!authHeader) {
|
|
1286
1330
|
return next(
|
|
@@ -1305,6 +1349,13 @@ var OAuth2Server = class {
|
|
|
1305
1349
|
)
|
|
1306
1350
|
);
|
|
1307
1351
|
}
|
|
1352
|
+
request.credentials = {
|
|
1353
|
+
clientId: credentials.name,
|
|
1354
|
+
clientSecret: credentials.pass
|
|
1355
|
+
};
|
|
1356
|
+
next();
|
|
1357
|
+
}
|
|
1358
|
+
async tokenHandler(request, response, next) {
|
|
1308
1359
|
const grantType = request.query.grant_type || request.body.grant_type;
|
|
1309
1360
|
if (!grantType) {
|
|
1310
1361
|
return next(
|
|
@@ -1319,8 +1370,15 @@ var OAuth2Server = class {
|
|
|
1319
1370
|
}
|
|
1320
1371
|
if (grantType === "client_credentials") {
|
|
1321
1372
|
const token = this.store.getClientToken(
|
|
1322
|
-
credentials.
|
|
1323
|
-
credentials.
|
|
1373
|
+
request.credentials.clientId,
|
|
1374
|
+
request.credentials.clientSecret,
|
|
1375
|
+
request.query.scope?.toString()
|
|
1376
|
+
);
|
|
1377
|
+
return response.status(200).send(token);
|
|
1378
|
+
} else if (grantType === "refresh_token") {
|
|
1379
|
+
const token = this.store.getClientToken(
|
|
1380
|
+
request.credentials.clientId,
|
|
1381
|
+
request.credentials.clientSecret,
|
|
1324
1382
|
request.query.scope?.toString()
|
|
1325
1383
|
);
|
|
1326
1384
|
return response.status(200).send(token);
|
|
@@ -1336,6 +1394,69 @@ var OAuth2Server = class {
|
|
|
1336
1394
|
);
|
|
1337
1395
|
}
|
|
1338
1396
|
}
|
|
1397
|
+
async customerTokenHandler(request, response, next) {
|
|
1398
|
+
const grantType = request.query.grant_type || request.body.grant_type;
|
|
1399
|
+
if (!grantType) {
|
|
1400
|
+
return next(
|
|
1401
|
+
new CommercetoolsError(
|
|
1402
|
+
{
|
|
1403
|
+
code: "invalid_request",
|
|
1404
|
+
message: "Missing required parameter: grant_type."
|
|
1405
|
+
},
|
|
1406
|
+
400
|
|
1407
|
+
)
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
if (grantType === "password") {
|
|
1411
|
+
const username = request.query.username || request.body.username;
|
|
1412
|
+
const password = hashPassword(
|
|
1413
|
+
request.query.password || request.body.password
|
|
1414
|
+
);
|
|
1415
|
+
const scope = request.query.scope?.toString() || request.body.scope?.toString();
|
|
1416
|
+
const result = this.customerRepository.query(
|
|
1417
|
+
{ projectKey: request.params.projectKey },
|
|
1418
|
+
{
|
|
1419
|
+
where: [`email = "${username}"`, `password = "${password}"`]
|
|
1420
|
+
}
|
|
1421
|
+
);
|
|
1422
|
+
if (result.count === 0) {
|
|
1423
|
+
return next(
|
|
1424
|
+
new CommercetoolsError(
|
|
1425
|
+
{
|
|
1426
|
+
code: "invalid_customer_account_credentials",
|
|
1427
|
+
message: "Customer account with the given credentials not found."
|
|
1428
|
+
},
|
|
1429
|
+
400
|
|
1430
|
+
)
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
const customer = result.results[0];
|
|
1434
|
+
const token = this.store.getCustomerToken(scope, customer.id);
|
|
1435
|
+
return response.status(200).send(token);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
async inStoreCustomerTokenHandler(request, response, next) {
|
|
1439
|
+
return next(
|
|
1440
|
+
new CommercetoolsError(
|
|
1441
|
+
{
|
|
1442
|
+
code: "invalid_client",
|
|
1443
|
+
message: "Not implemented yet in commercetools-mock"
|
|
1444
|
+
},
|
|
1445
|
+
401
|
|
1446
|
+
)
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
async anonymousTokenHandler(request, response, next) {
|
|
1450
|
+
return next(
|
|
1451
|
+
new CommercetoolsError(
|
|
1452
|
+
{
|
|
1453
|
+
code: "invalid_client",
|
|
1454
|
+
message: "Not implemented yet in commercetools-mock"
|
|
1455
|
+
},
|
|
1456
|
+
401
|
|
1457
|
+
)
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1339
1460
|
};
|
|
1340
1461
|
|
|
1341
1462
|
// src/projectAPI.ts
|
|
@@ -2812,11 +2933,29 @@ var CustomerRepository = class extends AbstractResourceRepository {
|
|
|
2812
2933
|
return "customer";
|
|
2813
2934
|
}
|
|
2814
2935
|
create(context, draft) {
|
|
2936
|
+
const results = this._storage.query(context.projectKey, this.getTypeId(), {
|
|
2937
|
+
where: [`email="${draft.email.toLocaleLowerCase()}"`]
|
|
2938
|
+
});
|
|
2939
|
+
if (results.count > 0) {
|
|
2940
|
+
throw new CommercetoolsError({
|
|
2941
|
+
code: "CustomerAlreadyExists",
|
|
2942
|
+
statusCode: 400,
|
|
2943
|
+
message: "There is already an existing customer with the provided email.",
|
|
2944
|
+
errors: [
|
|
2945
|
+
{
|
|
2946
|
+
code: "DuplicateField",
|
|
2947
|
+
message: `Customer with email '${draft.email}' already exists.`,
|
|
2948
|
+
duplicateValue: draft.email,
|
|
2949
|
+
field: "email"
|
|
2950
|
+
}
|
|
2951
|
+
]
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2815
2954
|
const resource = {
|
|
2816
2955
|
...getBaseResourceProperties(),
|
|
2817
2956
|
authenticationMode: draft.authenticationMode || "Password",
|
|
2818
|
-
email: draft.email,
|
|
2819
|
-
password: draft.password ?
|
|
2957
|
+
email: draft.email.toLowerCase(),
|
|
2958
|
+
password: draft.password ? hashPassword(draft.password) : void 0,
|
|
2820
2959
|
isEmailVerified: draft.isEmailVerified || false,
|
|
2821
2960
|
addresses: []
|
|
2822
2961
|
};
|
|
@@ -2854,7 +2993,7 @@ var CustomerRepository = class extends AbstractResourceRepository {
|
|
|
2854
2993
|
return;
|
|
2855
2994
|
}
|
|
2856
2995
|
if (authMode === "Password") {
|
|
2857
|
-
resource.password = password ?
|
|
2996
|
+
resource.password = password ? hashPassword(password) : void 0;
|
|
2858
2997
|
return;
|
|
2859
2998
|
}
|
|
2860
2999
|
throw new CommercetoolsError(
|
|
@@ -5984,7 +6123,7 @@ var MyCustomerService = class extends AbstractService {
|
|
|
5984
6123
|
}
|
|
5985
6124
|
signIn(request, response) {
|
|
5986
6125
|
const { email, password } = request.body;
|
|
5987
|
-
const encodedPassword =
|
|
6126
|
+
const encodedPassword = hashPassword(password);
|
|
5988
6127
|
const result = this.repository.query(getRepositoryContext(request), {
|
|
5989
6128
|
where: [`email = "${email}"`, `password = "${encodedPassword}"`]
|
|
5990
6129
|
});
|
|
@@ -6421,6 +6560,7 @@ var CommercetoolsMock = class {
|
|
|
6421
6560
|
}
|
|
6422
6561
|
createApp(options) {
|
|
6423
6562
|
this._repositories = createRepositories(this._storage);
|
|
6563
|
+
this._oauth2.setCustomerRepository(this._repositories.customer);
|
|
6424
6564
|
const app = express2();
|
|
6425
6565
|
const projectRouter = express2.Router({ mergeParams: true });
|
|
6426
6566
|
projectRouter.use(express2.json());
|
|
@@ -6446,6 +6586,13 @@ var CommercetoolsMock = class {
|
|
|
6446
6586
|
);
|
|
6447
6587
|
app.use((err, req, resp, next) => {
|
|
6448
6588
|
if (err instanceof CommercetoolsError) {
|
|
6589
|
+
if (err.errors?.length > 0) {
|
|
6590
|
+
return resp.status(err.statusCode).send({
|
|
6591
|
+
statusCode: err.statusCode,
|
|
6592
|
+
message: err.message,
|
|
6593
|
+
errors: err.errors
|
|
6594
|
+
});
|
|
6595
|
+
}
|
|
6449
6596
|
return resp.status(err.statusCode).send({
|
|
6450
6597
|
statusCode: err.statusCode,
|
|
6451
6598
|
message: err.message,
|
|
@@ -6469,42 +6616,46 @@ var CommercetoolsMock = class {
|
|
|
6469
6616
|
_globalListeners.forEach((listener) => listener.close());
|
|
6470
6617
|
}
|
|
6471
6618
|
}
|
|
6472
|
-
const
|
|
6619
|
+
const server = this.app;
|
|
6473
6620
|
this._mswServer = setupServer(
|
|
6474
6621
|
http.post(`${this.options.authHost}/oauth/*`, async ({ request }) => {
|
|
6475
|
-
const
|
|
6622
|
+
const body = await request.text();
|
|
6476
6623
|
const url = new URL(request.url);
|
|
6477
|
-
const
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6624
|
+
const headers = copyHeaders(request.headers);
|
|
6625
|
+
const res = await inject(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
|
|
6626
|
+
return new HttpResponse(res.body, {
|
|
6627
|
+
status: res.statusCode,
|
|
6628
|
+
headers: mapHeaderType(res.headers)
|
|
6481
6629
|
});
|
|
6482
6630
|
}),
|
|
6483
6631
|
http.get(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
6484
6632
|
const body = await request.text();
|
|
6485
6633
|
const url = new URL(request.url);
|
|
6486
|
-
const
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6634
|
+
const headers = copyHeaders(request.headers);
|
|
6635
|
+
const res = await inject(server).get(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
|
|
6636
|
+
return new HttpResponse(res.body, {
|
|
6637
|
+
status: res.statusCode,
|
|
6638
|
+
headers: mapHeaderType(res.headers)
|
|
6490
6639
|
});
|
|
6491
6640
|
}),
|
|
6492
6641
|
http.post(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
6493
6642
|
const body = await request.text();
|
|
6494
6643
|
const url = new URL(request.url);
|
|
6495
|
-
const
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6644
|
+
const headers = copyHeaders(request.headers);
|
|
6645
|
+
const res = await inject(server).post(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
|
|
6646
|
+
return new HttpResponse(res.body, {
|
|
6647
|
+
status: res.statusCode,
|
|
6648
|
+
headers: mapHeaderType(res.headers)
|
|
6499
6649
|
});
|
|
6500
6650
|
}),
|
|
6501
6651
|
http.delete(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
6502
6652
|
const body = await request.text();
|
|
6503
6653
|
const url = new URL(request.url);
|
|
6504
|
-
const
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6654
|
+
const headers = copyHeaders(request.headers);
|
|
6655
|
+
const res = await inject(server).delete(url.pathname + "?" + url.searchParams.toString()).body(body).headers(headers).end();
|
|
6656
|
+
return new HttpResponse(res.body, {
|
|
6657
|
+
status: res.statusCode,
|
|
6658
|
+
headers: mapHeaderType(res.headers)
|
|
6508
6659
|
});
|
|
6509
6660
|
})
|
|
6510
6661
|
);
|