@labdigital/commercetools-mock 2.0.0 → 2.1.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 CHANGED
@@ -53,10 +53,12 @@ var import_assert = __toESM(require("assert"), 1);
53
53
  var CommercetoolsError = class extends Error {
54
54
  info;
55
55
  statusCode;
56
+ errors;
56
57
  constructor(info, statusCode = 400) {
57
58
  super(info.message);
58
59
  this.info = info;
59
60
  this.statusCode = statusCode || 500;
61
+ this.errors = info.errors ?? [];
60
62
  }
61
63
  };
62
64
 
@@ -1256,6 +1258,16 @@ var OAuth2Store = class {
1256
1258
  this.tokens.push(token);
1257
1259
  return token;
1258
1260
  }
1261
+ getCustomerToken(scope, customerId) {
1262
+ const token = {
1263
+ access_token: (0, import_crypto.randomBytes)(16).toString("base64"),
1264
+ token_type: "Bearer",
1265
+ expires_in: 172800,
1266
+ scope: scope ? `${scope} custome_id:${customerId}` : `customer_id: ${customerId}`
1267
+ };
1268
+ this.tokens.push(token);
1269
+ return token;
1270
+ }
1259
1271
  validateToken(token) {
1260
1272
  if (!this.validate)
1261
1273
  return true;
@@ -1277,16 +1289,36 @@ var getBearerToken = (request) => {
1277
1289
  return void 0;
1278
1290
  };
1279
1291
 
1292
+ // src/lib/password.ts
1293
+ var hashPassword = (clearPassword) => Buffer.from(clearPassword).toString("base64");
1294
+
1280
1295
  // src/oauth/server.ts
1281
1296
  var OAuth2Server = class {
1282
1297
  store;
1298
+ customerRepository;
1283
1299
  constructor(options) {
1284
1300
  this.store = new OAuth2Store(options.validate);
1285
1301
  }
1302
+ setCustomerRepository(repository) {
1303
+ this.customerRepository = repository;
1304
+ }
1286
1305
  createRouter() {
1287
1306
  const router = import_express.default.Router();
1288
1307
  router.use(import_body_parser.default.urlencoded({ extended: true }));
1308
+ router.use(this.validateClientCredentials.bind(this));
1289
1309
  router.post("/token", this.tokenHandler.bind(this));
1310
+ router.post(
1311
+ "/:projectKey/customers/token",
1312
+ this.customerTokenHandler.bind(this)
1313
+ );
1314
+ router.post(
1315
+ "/:projectKey/in-store/key=:storeKey/customers/token",
1316
+ this.inStoreCustomerTokenHandler.bind(this)
1317
+ );
1318
+ router.post(
1319
+ "/:projectKey/anonymous/token",
1320
+ this.anonymousTokenHandler.bind(this)
1321
+ );
1290
1322
  return router;
1291
1323
  }
1292
1324
  createMiddleware() {
@@ -1317,7 +1349,7 @@ var OAuth2Server = class {
1317
1349
  next();
1318
1350
  };
1319
1351
  }
1320
- async tokenHandler(request, response, next) {
1352
+ async validateClientCredentials(request, response, next) {
1321
1353
  const authHeader = request.header("Authorization");
1322
1354
  if (!authHeader) {
1323
1355
  return next(
@@ -1342,6 +1374,13 @@ var OAuth2Server = class {
1342
1374
  )
1343
1375
  );
1344
1376
  }
1377
+ request.credentials = {
1378
+ clientId: credentials.name,
1379
+ clientSecret: credentials.pass
1380
+ };
1381
+ next();
1382
+ }
1383
+ async tokenHandler(request, response, next) {
1345
1384
  const grantType = request.query.grant_type || request.body.grant_type;
1346
1385
  if (!grantType) {
1347
1386
  return next(
@@ -1356,8 +1395,15 @@ var OAuth2Server = class {
1356
1395
  }
1357
1396
  if (grantType === "client_credentials") {
1358
1397
  const token = this.store.getClientToken(
1359
- credentials.name,
1360
- credentials.pass,
1398
+ request.credentials.clientId,
1399
+ request.credentials.clientSecret,
1400
+ request.query.scope?.toString()
1401
+ );
1402
+ return response.status(200).send(token);
1403
+ } else if (grantType === "refresh_token") {
1404
+ const token = this.store.getClientToken(
1405
+ request.credentials.clientId,
1406
+ request.credentials.clientSecret,
1361
1407
  request.query.scope?.toString()
1362
1408
  );
1363
1409
  return response.status(200).send(token);
@@ -1373,6 +1419,69 @@ var OAuth2Server = class {
1373
1419
  );
1374
1420
  }
1375
1421
  }
1422
+ async customerTokenHandler(request, response, next) {
1423
+ const grantType = request.query.grant_type || request.body.grant_type;
1424
+ if (!grantType) {
1425
+ return next(
1426
+ new CommercetoolsError(
1427
+ {
1428
+ code: "invalid_request",
1429
+ message: "Missing required parameter: grant_type."
1430
+ },
1431
+ 400
1432
+ )
1433
+ );
1434
+ }
1435
+ if (grantType === "password") {
1436
+ const username = request.query.username || request.body.username;
1437
+ const password = hashPassword(
1438
+ request.query.password || request.body.password
1439
+ );
1440
+ const scope = request.query.scope?.toString() || request.body.scope?.toString();
1441
+ const result = this.customerRepository.query(
1442
+ { projectKey: request.params.projectKey },
1443
+ {
1444
+ where: [`email = "${username}"`, `password = "${password}"`]
1445
+ }
1446
+ );
1447
+ if (result.count === 0) {
1448
+ return next(
1449
+ new CommercetoolsError(
1450
+ {
1451
+ code: "invalid_customer_account_credentials",
1452
+ message: "Customer account with the given credentials not found."
1453
+ },
1454
+ 400
1455
+ )
1456
+ );
1457
+ }
1458
+ const customer = result.results[0];
1459
+ const token = this.store.getCustomerToken(scope, customer.id);
1460
+ return response.status(200).send(token);
1461
+ }
1462
+ }
1463
+ async inStoreCustomerTokenHandler(request, response, next) {
1464
+ return next(
1465
+ new CommercetoolsError(
1466
+ {
1467
+ code: "invalid_client",
1468
+ message: "Not implemented yet in commercetools-mock"
1469
+ },
1470
+ 401
1471
+ )
1472
+ );
1473
+ }
1474
+ async anonymousTokenHandler(request, response, next) {
1475
+ return next(
1476
+ new CommercetoolsError(
1477
+ {
1478
+ code: "invalid_client",
1479
+ message: "Not implemented yet in commercetools-mock"
1480
+ },
1481
+ 401
1482
+ )
1483
+ );
1484
+ }
1376
1485
  };
1377
1486
 
1378
1487
  // src/projectAPI.ts
@@ -2849,11 +2958,29 @@ var CustomerRepository = class extends AbstractResourceRepository {
2849
2958
  return "customer";
2850
2959
  }
2851
2960
  create(context, draft) {
2961
+ const results = this._storage.query(context.projectKey, this.getTypeId(), {
2962
+ where: [`email="${draft.email.toLocaleLowerCase()}"`]
2963
+ });
2964
+ if (results.count > 0) {
2965
+ throw new CommercetoolsError({
2966
+ code: "CustomerAlreadyExists",
2967
+ statusCode: 400,
2968
+ message: "There is already an existing customer with the provided email.",
2969
+ errors: [
2970
+ {
2971
+ code: "DuplicateField",
2972
+ message: `Customer with email '${draft.email}' already exists.`,
2973
+ duplicateValue: draft.email,
2974
+ field: "email"
2975
+ }
2976
+ ]
2977
+ });
2978
+ }
2852
2979
  const resource = {
2853
2980
  ...getBaseResourceProperties(),
2854
2981
  authenticationMode: draft.authenticationMode || "Password",
2855
- email: draft.email,
2856
- password: draft.password ? Buffer.from(draft.password).toString("base64") : void 0,
2982
+ email: draft.email.toLowerCase(),
2983
+ password: draft.password ? hashPassword(draft.password) : void 0,
2857
2984
  isEmailVerified: draft.isEmailVerified || false,
2858
2985
  addresses: []
2859
2986
  };
@@ -2891,7 +3018,7 @@ var CustomerRepository = class extends AbstractResourceRepository {
2891
3018
  return;
2892
3019
  }
2893
3020
  if (authMode === "Password") {
2894
- resource.password = password ? Buffer.from(password).toString("base64") : void 0;
3021
+ resource.password = password ? hashPassword(password) : void 0;
2895
3022
  return;
2896
3023
  }
2897
3024
  throw new CommercetoolsError(
@@ -6021,7 +6148,7 @@ var MyCustomerService = class extends AbstractService {
6021
6148
  }
6022
6149
  signIn(request, response) {
6023
6150
  const { email, password } = request.body;
6024
- const encodedPassword = Buffer.from(password).toString("base64");
6151
+ const encodedPassword = hashPassword(password);
6025
6152
  const result = this.repository.query(getRepositoryContext(request), {
6026
6153
  where: [`email = "${email}"`, `password = "${encodedPassword}"`]
6027
6154
  });
@@ -6458,6 +6585,7 @@ var CommercetoolsMock = class {
6458
6585
  }
6459
6586
  createApp(options) {
6460
6587
  this._repositories = createRepositories(this._storage);
6588
+ this._oauth2.setCustomerRepository(this._repositories.customer);
6461
6589
  const app = (0, import_express6.default)();
6462
6590
  const projectRouter = import_express6.default.Router({ mergeParams: true });
6463
6591
  projectRouter.use(import_express6.default.json());
@@ -6483,6 +6611,13 @@ var CommercetoolsMock = class {
6483
6611
  );
6484
6612
  app.use((err, req, resp, next) => {
6485
6613
  if (err instanceof CommercetoolsError) {
6614
+ if (err.errors?.length > 0) {
6615
+ return resp.status(err.statusCode).send({
6616
+ statusCode: err.statusCode,
6617
+ message: err.message,
6618
+ errors: err.errors
6619
+ });
6620
+ }
6486
6621
  return resp.status(err.statusCode).send({
6487
6622
  statusCode: err.statusCode,
6488
6623
  message: err.message,