@commercetools/connect-payments-sdk 0.0.1 → 0.0.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/CHANGELOG.md +12 -0
- package/dist/api/context/types/request-context.type.d.ts +2 -2
- package/dist/api/handlers/config.handler.d.ts +1 -1
- package/dist/api/handlers/status.handler.d.ts +12 -6
- package/dist/api/handlers/status.handler.js +4 -7
- package/dist/api/handlers/types/handler.type.d.ts +2 -2
- package/dist/api/hooks/jwt-auth.hook.d.ts +16 -0
- package/dist/api/hooks/jwt-auth.hook.js +22 -0
- package/dist/api/hooks/oauth2-auth.hook.d.ts +16 -0
- package/dist/api/hooks/oauth2-auth.hook.js +22 -0
- package/dist/api/hooks/session-auth.hook.d.ts +14 -13
- package/dist/api/hooks/session-auth.hook.js +18 -27
- package/dist/api/hooks/types/hook.type.d.ts +10 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.js +3 -0
- package/dist/commercetools/index.d.ts +2 -0
- package/dist/commercetools/services/ct-authorization.service.d.ts +18 -0
- package/dist/commercetools/services/ct-authorization.service.js +42 -0
- package/dist/commercetools/services/ct-payment.service.d.ts +6 -1
- package/dist/commercetools/services/ct-payment.service.js +72 -0
- package/dist/commercetools/services/ct-session.service.d.ts +16 -0
- package/dist/commercetools/services/ct-session.service.js +45 -0
- package/dist/commercetools/types/api.type.d.ts +11 -0
- package/dist/commercetools/types/authorization.type.d.ts +9 -0
- package/dist/commercetools/types/payment.type.d.ts +10 -0
- package/dist/commercetools/types/session.type.d.ts +28 -0
- package/dist/commercetools/types/session.type.js +2 -0
- package/dist/errorx/errorx.d.ts +4 -1
- package/dist/errorx/errorx.js +15 -4
- package/dist/index.d.ts +8 -8
- package/dist/index.js +38 -12
- package/dist/security/authn/authns.d.ts +49 -0
- package/dist/security/authn/authns.js +123 -0
- package/dist/security/authn/bearer-utils.d.ts +1 -0
- package/dist/security/authn/bearer-utils.js +19 -0
- package/dist/security/authn/jwt-authn-manager.d.ts +12 -0
- package/dist/security/authn/jwt-authn-manager.js +33 -0
- package/dist/security/authn/oauth2-authn-manager.d.ts +17 -0
- package/dist/security/authn/oauth2-authn-manager.js +65 -0
- package/dist/security/authn/session-authn-manager.d.ts +10 -0
- package/dist/security/authn/session-authn-manager.js +25 -0
- package/dist/security/authn/types/authn.type.d.ts +27 -0
- package/dist/security/authn/types/authn.type.js +2 -0
- package/dist/security/index.d.ts +6 -2
- package/dist/security/index.js +6 -2
- package/dist/security/services/jwt.service.d.ts +10 -0
- package/dist/security/services/jwt.service.js +40 -0
- package/dist/security/services/oauth2.service.d.ts +7 -14
- package/dist/security/services/oauth2.service.js +22 -35
- package/dist/security/services/types/jwt.type.d.ts +5 -0
- package/dist/security/services/types/jwt.type.js +2 -0
- package/dist/security/services/types/oauth2.type.d.ts +14 -0
- package/dist/security/services/types/oauth2.type.js +2 -0
- package/package.json +5 -3
- package/.github/workflows/ci.yml +0 -34
- package/.github/workflows/release.yml +0 -46
- package/.husky/pre-commit +0 -4
- package/dist/security/auth/session.auth.d.ts +0 -20
- package/dist/security/auth/session.auth.js +0 -54
- package/dist/security/types/oauth2.type.d.ts +0 -13
- package/dist/security/types/session.type.d.ts +0 -10
- /package/dist/{security/types/oauth2.type.js → api/hooks/types/hook.type.js} +0 -0
- /package/dist/{security/types/session.type.js → commercetools/types/authorization.type.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @commercetools/connect-payments-sdk
|
|
2
2
|
|
|
3
|
+
## 0.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ab6200f: Support jwt, oauth2 authentication and support for authority based authorization
|
|
8
|
+
|
|
9
|
+
## 0.0.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- f3f238f: Authentication and authorization layer via session API
|
|
14
|
+
|
|
3
15
|
## 0.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Authentication } from '../../../security';
|
|
2
2
|
/**
|
|
3
3
|
* Context provider interface
|
|
4
4
|
*/
|
|
@@ -12,5 +12,5 @@ export interface ContextProvider<T> {
|
|
|
12
12
|
export type RequestContextData = {
|
|
13
13
|
correlationId: string;
|
|
14
14
|
requestId: string;
|
|
15
|
-
|
|
15
|
+
authentication?: Authentication;
|
|
16
16
|
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommercetoolsAuthorizationService } from '../../commercetools';
|
|
2
2
|
import { HandlerResponse } from './types/handler.type';
|
|
3
|
+
type HealthCheckStatus = {
|
|
4
|
+
status: 'OK' | 'Partially Available' | 'Unavailable';
|
|
5
|
+
timestamp: string;
|
|
6
|
+
checks: HealthCheckResult[];
|
|
7
|
+
version: string;
|
|
8
|
+
metadata?: object;
|
|
9
|
+
};
|
|
3
10
|
export type HealthCheckResult = {
|
|
4
11
|
name: string;
|
|
5
12
|
status: 'UP' | 'DOWN';
|
|
@@ -10,16 +17,15 @@ export declare const statusHandler: (options: {
|
|
|
10
17
|
timeout: number;
|
|
11
18
|
checks: HealthCheck[];
|
|
12
19
|
metadataFn?: () => Promise<object> | object;
|
|
13
|
-
}) => () => Promise<HandlerResponse
|
|
20
|
+
}) => () => Promise<HandlerResponse<HealthCheckStatus>>;
|
|
14
21
|
/**
|
|
15
22
|
* Check if CoCo permissions are available
|
|
16
23
|
* @param opts
|
|
17
24
|
* @returns
|
|
18
25
|
*/
|
|
19
|
-
export declare const
|
|
20
|
-
|
|
21
|
-
clientId: string;
|
|
22
|
-
clientSecret: string;
|
|
26
|
+
export declare const healthCheckCommercetoolsPermissions: (opts: {
|
|
27
|
+
ctAuthorizationService: CommercetoolsAuthorizationService;
|
|
23
28
|
projectKey: string;
|
|
24
29
|
requiredPermissions: string[];
|
|
25
30
|
}) => () => Promise<HealthCheckResult>;
|
|
31
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.healthCheckCommercetoolsPermissions = exports.statusHandler = void 0;
|
|
4
4
|
const statusHandler = (options) => async () => {
|
|
5
5
|
const status = {
|
|
6
6
|
timestamp: new Date().toISOString(),
|
|
@@ -45,11 +45,8 @@ exports.statusHandler = statusHandler;
|
|
|
45
45
|
* @param opts
|
|
46
46
|
* @returns
|
|
47
47
|
*/
|
|
48
|
-
const
|
|
49
|
-
const token = await opts.
|
|
50
|
-
clientId: opts.clientId,
|
|
51
|
-
clientSecret: opts.clientSecret,
|
|
52
|
-
});
|
|
48
|
+
const healthCheckCommercetoolsPermissions = (opts) => async () => {
|
|
49
|
+
const token = await opts.ctAuthorizationService.getAccessToken();
|
|
53
50
|
const foundAll = opts.requiredPermissions.every((currentScope) => token.scope.split(' ').some((scopeInToken) => scopeInToken === `${currentScope}:${opts.projectKey}`));
|
|
54
51
|
if (foundAll) {
|
|
55
52
|
return {
|
|
@@ -70,4 +67,4 @@ const healthCheckCoCoPermissions = (opts) => async () => {
|
|
|
70
67
|
},
|
|
71
68
|
};
|
|
72
69
|
};
|
|
73
|
-
exports.
|
|
70
|
+
exports.healthCheckCommercetoolsPermissions = healthCheckCommercetoolsPermissions;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
3
|
+
import { JWTAuthenticationManager } from '../../security/authn/jwt-authn-manager';
|
|
4
|
+
import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
|
|
5
|
+
import { AuthenticationHook } from './types/hook.type';
|
|
6
|
+
export declare class JWTAuthenticationHook implements AuthenticationHook {
|
|
7
|
+
private authenticationManager;
|
|
8
|
+
private contextProvider;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
authenticationManager: JWTAuthenticationManager;
|
|
11
|
+
contextProvider: ContextProvider<RequestContextData>;
|
|
12
|
+
});
|
|
13
|
+
authenticate(): (request: {
|
|
14
|
+
headers: IncomingHttpHeaders;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JWTAuthenticationHook = void 0;
|
|
4
|
+
const security_1 = require("../../security");
|
|
5
|
+
class JWTAuthenticationHook {
|
|
6
|
+
authenticationManager;
|
|
7
|
+
contextProvider;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.authenticationManager = opts.authenticationManager;
|
|
10
|
+
this.contextProvider = opts.contextProvider;
|
|
11
|
+
}
|
|
12
|
+
authenticate() {
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
|
|
15
|
+
const authn = await this.authenticationManager.authenticate(authorizationHeader);
|
|
16
|
+
this.contextProvider.updateContextData({
|
|
17
|
+
authentication: authn,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.JWTAuthenticationHook = JWTAuthenticationHook;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
3
|
+
import { Oauth2AuthenticationManager } from '../../security/authn/oauth2-authn-manager';
|
|
4
|
+
import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
|
|
5
|
+
import { AuthenticationHook } from './types/hook.type';
|
|
6
|
+
export declare class Oauth2AuthenticationHook implements AuthenticationHook {
|
|
7
|
+
private authenticationManager;
|
|
8
|
+
private contextProvider;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
authenticationManager: Oauth2AuthenticationManager;
|
|
11
|
+
contextProvider: ContextProvider<RequestContextData>;
|
|
12
|
+
});
|
|
13
|
+
authenticate(): (request: {
|
|
14
|
+
headers: IncomingHttpHeaders;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Oauth2AuthenticationHook = void 0;
|
|
4
|
+
const security_1 = require("../../security");
|
|
5
|
+
class Oauth2AuthenticationHook {
|
|
6
|
+
authenticationManager;
|
|
7
|
+
contextProvider;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.authenticationManager = opts.authenticationManager;
|
|
10
|
+
this.contextProvider = opts.contextProvider;
|
|
11
|
+
}
|
|
12
|
+
authenticate() {
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
|
|
15
|
+
const authn = await this.authenticationManager.authenticate(authorizationHeader);
|
|
16
|
+
this.contextProvider.updateContextData({
|
|
17
|
+
authentication: authn,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.Oauth2AuthenticationHook = Oauth2AuthenticationHook;
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { IncomingHttpHeaders } from 'node:http';
|
|
2
|
-
import { SessionAuthenticator } from '../../security/types/session.type';
|
|
3
3
|
import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}) => Promise<void>;
|
|
4
|
+
import { SessionAuthenticationManager } from '../../security';
|
|
5
|
+
import { AuthenticationHook } from './types/hook.type';
|
|
6
|
+
export declare class SessionAuthenticationHook implements AuthenticationHook {
|
|
7
|
+
private authenticationManager;
|
|
8
|
+
private contextProvider;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
authenticationManager: SessionAuthenticationManager;
|
|
11
|
+
contextProvider: ContextProvider<RequestContextData>;
|
|
12
|
+
});
|
|
13
|
+
authenticate(): (request: {
|
|
14
|
+
headers: IncomingHttpHeaders;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
}
|
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const sessionId = req.headers['x-session-id'];
|
|
12
|
-
if (sessionId) {
|
|
13
|
-
const sessionData = await opts.sessionAuthenticator.introspectSession({
|
|
14
|
-
sessionId,
|
|
15
|
-
});
|
|
16
|
-
opts.contextProvider.updateContextData({
|
|
17
|
-
sessionData,
|
|
18
|
-
});
|
|
19
|
-
//updateSessionContext(sessionData);
|
|
3
|
+
exports.SessionAuthenticationHook = void 0;
|
|
4
|
+
const security_1 = require("../../security");
|
|
5
|
+
class SessionAuthenticationHook {
|
|
6
|
+
authenticationManager;
|
|
7
|
+
contextProvider;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.authenticationManager = opts.authenticationManager;
|
|
10
|
+
this.contextProvider = opts.contextProvider;
|
|
20
11
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
}
|
|
12
|
+
authenticate() {
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const sessionIdAuthn = new security_1.HeaderBasedAuthentication(request.headers['x-session-id']);
|
|
15
|
+
const authn = await this.authenticationManager.authenticate(sessionIdAuthn);
|
|
16
|
+
this.contextProvider.updateContextData({
|
|
17
|
+
authentication: authn,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
29
20
|
}
|
|
30
|
-
}
|
|
31
|
-
exports.
|
|
21
|
+
}
|
|
22
|
+
exports.SessionAuthenticationHook = SessionAuthenticationHook;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
3
|
+
export interface AuthenticationHook {
|
|
4
|
+
authenticate(): (request: {
|
|
5
|
+
headers: IncomingHttpHeaders;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export interface AuthorizationHook {
|
|
9
|
+
authorize(...authorities: string[]): () => Promise<void>;
|
|
10
|
+
}
|
package/dist/api/index.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ export * from './context/request-context.provider';
|
|
|
2
2
|
export * from './context/types/request-context.type';
|
|
3
3
|
export * from './handlers/config.handler';
|
|
4
4
|
export * from './handlers/status.handler';
|
|
5
|
+
export * from './hooks/jwt-auth.hook';
|
|
6
|
+
export * from './hooks/oauth2-auth.hook';
|
|
5
7
|
export * from './hooks/session-auth.hook';
|
|
8
|
+
export * from './hooks/types/hook.type';
|
package/dist/api/index.js
CHANGED
|
@@ -18,4 +18,7 @@ __exportStar(require("./context/request-context.provider"), exports);
|
|
|
18
18
|
__exportStar(require("./context/types/request-context.type"), exports);
|
|
19
19
|
__exportStar(require("./handlers/config.handler"), exports);
|
|
20
20
|
__exportStar(require("./handlers/status.handler"), exports);
|
|
21
|
+
__exportStar(require("./hooks/jwt-auth.hook"), exports);
|
|
22
|
+
__exportStar(require("./hooks/oauth2-auth.hook"), exports);
|
|
21
23
|
__exportStar(require("./hooks/session-auth.hook"), exports);
|
|
24
|
+
__exportStar(require("./hooks/types/hook.type"), exports);
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { CartService as CommercetoolsCartService } from './types/cart.type';
|
|
2
2
|
export { PaymentService as CommercetoolsPaymentService, TransactionData, UpdatePayment } from './types/payment.type';
|
|
3
|
+
export { SessionService as CommercetoolsSessionService, Session } from './types/session.type';
|
|
4
|
+
export { AuthorizationService as CommercetoolsAuthorizationService } from './types/authorization.type';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Fetch } from '../../fetch/types/fetch.type';
|
|
2
|
+
import { Logger } from '../../logger';
|
|
3
|
+
import { AuthorizationService, CommercetoolsToken } from '../types/authorization.type';
|
|
4
|
+
export declare class DefaultAuthorizationService implements AuthorizationService {
|
|
5
|
+
private authUrl;
|
|
6
|
+
private clientId;
|
|
7
|
+
private clientSecret;
|
|
8
|
+
private fetch;
|
|
9
|
+
private logger?;
|
|
10
|
+
constructor(opts: {
|
|
11
|
+
authUrl: string;
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
fetch: Fetch;
|
|
15
|
+
logger?: Logger;
|
|
16
|
+
});
|
|
17
|
+
getAccessToken(): Promise<CommercetoolsToken>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultAuthorizationService = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx/errorx");
|
|
5
|
+
class DefaultAuthorizationService {
|
|
6
|
+
authUrl;
|
|
7
|
+
clientId;
|
|
8
|
+
clientSecret;
|
|
9
|
+
fetch;
|
|
10
|
+
logger;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.authUrl = opts.authUrl;
|
|
13
|
+
this.clientId = opts.clientId;
|
|
14
|
+
this.clientSecret = opts.clientSecret;
|
|
15
|
+
this.fetch = opts.fetch;
|
|
16
|
+
this.logger = opts.logger;
|
|
17
|
+
}
|
|
18
|
+
async getAccessToken() {
|
|
19
|
+
const encodedCredentials = btoa(`${this.clientId}:${this.clientSecret}`);
|
|
20
|
+
const urlencoded = new URLSearchParams();
|
|
21
|
+
urlencoded.append('grant_type', 'client_credentials');
|
|
22
|
+
const response = await this.fetch(`${this.authUrl}/oauth/token`, {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
26
|
+
Authorization: `Basic ${encodedCredentials}`,
|
|
27
|
+
},
|
|
28
|
+
body: urlencoded,
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new errorx_1.ErrorGeneral(undefined, {
|
|
32
|
+
privateMessage: 'Failed to get auth token',
|
|
33
|
+
privateFields: {
|
|
34
|
+
responseStatus: response.status,
|
|
35
|
+
responseText: await response.text(),
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return (await response.json());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.DefaultAuthorizationService = DefaultAuthorizationService;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Payment, PaymentDraft } from '@commercetools/platform-sdk';
|
|
2
|
-
import { GetPayment, PaymentService, PaymentServiceOptions, UpdatePayment } from '../types/payment.type';
|
|
2
|
+
import { GetPayment, PaymentModificationValidation, PaymentModificationValidationResult, PaymentService, PaymentServiceOptions, UpdatePayment } from '../types/payment.type';
|
|
3
3
|
/**
|
|
4
4
|
* This is the default implementation of the PaymentService interface.
|
|
5
5
|
*/
|
|
@@ -9,6 +9,7 @@ export declare class DefaultPaymentService implements PaymentService {
|
|
|
9
9
|
getPayment(opts: GetPayment): Promise<Payment>;
|
|
10
10
|
createPayment(draft: PaymentDraft): Promise<Payment>;
|
|
11
11
|
updatePayment(opts: UpdatePayment): Promise<Payment>;
|
|
12
|
+
validatePaymentModification(opts: PaymentModificationValidation): PaymentModificationValidationResult;
|
|
12
13
|
private consolidateUpdateActions;
|
|
13
14
|
private populateSetInterfaceIdAction;
|
|
14
15
|
private populateChangeTransactionInteractionId;
|
|
@@ -17,4 +18,8 @@ export declare class DefaultPaymentService implements PaymentService {
|
|
|
17
18
|
private populateSetPaymentMethod;
|
|
18
19
|
private findMatchingTransactions;
|
|
19
20
|
private consolidateTransactionChanges;
|
|
21
|
+
private validateCancelAuthorization;
|
|
22
|
+
private validateCapturePayment;
|
|
23
|
+
private validateRefundPayment;
|
|
24
|
+
private calculateTotalAmount;
|
|
20
25
|
}
|
|
@@ -44,6 +44,18 @@ class DefaultPaymentService {
|
|
|
44
44
|
}
|
|
45
45
|
throw err;
|
|
46
46
|
}
|
|
47
|
+
validatePaymentModification(opts) {
|
|
48
|
+
switch (opts.type) {
|
|
49
|
+
case 'cancelAuthorization':
|
|
50
|
+
return this.validateCancelAuthorization(opts.payment);
|
|
51
|
+
case 'capturePayment':
|
|
52
|
+
return this.validateCapturePayment(opts.payment, opts.amount);
|
|
53
|
+
case 'refundPayment':
|
|
54
|
+
return this.validateRefundPayment(opts.payment, opts.amount);
|
|
55
|
+
default:
|
|
56
|
+
throw new Error(`Invalid payment modification type: ${opts.type}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
47
59
|
consolidateUpdateActions(payment, updateInfo) {
|
|
48
60
|
const actions = [];
|
|
49
61
|
if (!payment.interfaceId && updateInfo.pspReference) {
|
|
@@ -125,5 +137,65 @@ class DefaultPaymentService {
|
|
|
125
137
|
}
|
|
126
138
|
return actions;
|
|
127
139
|
}
|
|
140
|
+
validateCancelAuthorization(payment) {
|
|
141
|
+
const totalAuthorized = this.calculateTotalAmount(payment, 'Authorization', payment.amountPlanned.currencyCode);
|
|
142
|
+
if (totalAuthorized === 0) {
|
|
143
|
+
return { isValid: false, reason: `No authorization transaction found for resource ${payment.id}.` };
|
|
144
|
+
}
|
|
145
|
+
const totalCaptured = this.calculateTotalAmount(payment, 'Charge', payment.amountPlanned.currencyCode);
|
|
146
|
+
if (totalCaptured > 0) {
|
|
147
|
+
return { isValid: false, reason: `Resource ${payment.id} has already been charged.` };
|
|
148
|
+
}
|
|
149
|
+
return { isValid: true };
|
|
150
|
+
}
|
|
151
|
+
validateCapturePayment(payment, amount) {
|
|
152
|
+
if (payment.amountPlanned.currencyCode !== amount.currencyCode) {
|
|
153
|
+
return {
|
|
154
|
+
isValid: false,
|
|
155
|
+
reason: `Invalid currency ${amount.currencyCode} for resource ${payment.id}, expected ${payment.amountPlanned.currencyCode}`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const totalAuthorized = this.calculateTotalAmount(payment, 'Authorization', amount.currencyCode);
|
|
159
|
+
if (totalAuthorized === 0) {
|
|
160
|
+
return { isValid: false, reason: `No authorization transaction found for resource ${payment.id}.` };
|
|
161
|
+
}
|
|
162
|
+
const totalCaptured = this.calculateTotalAmount(payment, 'Charge', amount.currencyCode);
|
|
163
|
+
const allowedAmount = totalAuthorized - totalCaptured;
|
|
164
|
+
if (amount.centAmount > allowedAmount) {
|
|
165
|
+
return {
|
|
166
|
+
isValid: false,
|
|
167
|
+
reason: `The amount to capture ${amount.centAmount} exceeds the allowed amount [${allowedAmount}]`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { isValid: true };
|
|
171
|
+
}
|
|
172
|
+
validateRefundPayment(payment, amount) {
|
|
173
|
+
if (payment.amountPlanned.currencyCode !== amount.currencyCode) {
|
|
174
|
+
return {
|
|
175
|
+
isValid: false,
|
|
176
|
+
reason: `Invalid currency ${amount.currencyCode} for resource ${payment.id}, expected ${payment.amountPlanned.currencyCode}`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const totalCaptured = this.calculateTotalAmount(payment, 'Charge', amount.currencyCode);
|
|
180
|
+
if (totalCaptured === 0) {
|
|
181
|
+
return { isValid: false, reason: `No charge transaction found for resource ${payment.id}.` };
|
|
182
|
+
}
|
|
183
|
+
const totalRefunded = this.calculateTotalAmount(payment, 'Refund', amount.currencyCode);
|
|
184
|
+
const allowedAmount = totalCaptured - totalRefunded;
|
|
185
|
+
if (amount.centAmount > allowedAmount) {
|
|
186
|
+
return {
|
|
187
|
+
isValid: false,
|
|
188
|
+
reason: `The amount to refund ${amount.centAmount} exceeds the allowed amount [${allowedAmount}]`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return { isValid: true };
|
|
192
|
+
}
|
|
193
|
+
calculateTotalAmount(payment, type, currencyCode) {
|
|
194
|
+
return payment.transactions
|
|
195
|
+
.filter((transaction) => transaction.type === type &&
|
|
196
|
+
transaction.state === 'Success' &&
|
|
197
|
+
transaction.amount.currencyCode === currencyCode)
|
|
198
|
+
.reduce((total, transaction) => total + transaction.amount.centAmount, 0);
|
|
199
|
+
}
|
|
128
200
|
}
|
|
129
201
|
exports.DefaultPaymentService = DefaultPaymentService;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AuthorizationService, CommercetoolsToken } from '../types/authorization.type';
|
|
2
|
+
import { Session, SessionService } from '../types/session.type';
|
|
3
|
+
export declare class DefaultSessionService implements SessionService {
|
|
4
|
+
private authorizationService;
|
|
5
|
+
private sessionUrl;
|
|
6
|
+
private projectKey;
|
|
7
|
+
protected token: CommercetoolsToken;
|
|
8
|
+
constructor(opts: {
|
|
9
|
+
authorizationService: AuthorizationService;
|
|
10
|
+
sessionUrl: string;
|
|
11
|
+
projectKey: string;
|
|
12
|
+
});
|
|
13
|
+
verifySession(sessionId: string): Promise<Session>;
|
|
14
|
+
getCartFromSession(session: Session): string;
|
|
15
|
+
getAllowedPaymentMethodsFromSession(session: Session): string[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultSessionService = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx/errorx");
|
|
5
|
+
class DefaultSessionService {
|
|
6
|
+
authorizationService;
|
|
7
|
+
sessionUrl;
|
|
8
|
+
projectKey;
|
|
9
|
+
token;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.authorizationService = opts.authorizationService;
|
|
12
|
+
this.sessionUrl = opts.sessionUrl;
|
|
13
|
+
this.projectKey = opts.projectKey;
|
|
14
|
+
}
|
|
15
|
+
async verifySession(sessionId) {
|
|
16
|
+
if (!this.token) {
|
|
17
|
+
this.token = await this.authorizationService.getAccessToken();
|
|
18
|
+
}
|
|
19
|
+
const res = await fetch(`${this.sessionUrl}/${this.projectKey}/sessions/${sessionId}`, {
|
|
20
|
+
method: 'GET',
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
Authorization: `Bearer ${this.token.access_token}`,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new errorx_1.ErrorGeneral('Could not get session');
|
|
28
|
+
}
|
|
29
|
+
const session = (await res.json());
|
|
30
|
+
if (session.state !== 'ACTIVE') {
|
|
31
|
+
throw new errorx_1.ErrorAuthErrorResponse();
|
|
32
|
+
}
|
|
33
|
+
return session;
|
|
34
|
+
}
|
|
35
|
+
getCartFromSession(session) {
|
|
36
|
+
if (!session.activeCart?.cartRef?.id) {
|
|
37
|
+
throw new errorx_1.ErrorAuthErrorResponse();
|
|
38
|
+
}
|
|
39
|
+
return session.activeCart.cartRef.id;
|
|
40
|
+
}
|
|
41
|
+
getAllowedPaymentMethodsFromSession(session) {
|
|
42
|
+
return session.metadata?.allowedPaymentMethods || [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.DefaultSessionService = DefaultSessionService;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Cart, Payment, PaymentDraft, PaymentPagedQueryResponse, PaymentUpdateAction } from '@commercetools/platform-sdk';
|
|
2
2
|
import { ByProjectKeyRequestBuilder } from '@commercetools/platform-sdk/dist/declarations/src/generated/client/by-project-key-request-builder';
|
|
3
3
|
export type CommercetoolsClient = ByProjectKeyRequestBuilder;
|
|
4
|
+
export type CommercetoolsSessionClient = ByProjectKeyRequestBuilder;
|
|
4
5
|
export interface APIOpts {
|
|
5
6
|
client: CommercetoolsClient;
|
|
6
7
|
}
|
|
@@ -16,6 +17,16 @@ export type UpdatePayment = {
|
|
|
16
17
|
resource: UpdateResource;
|
|
17
18
|
actions: PaymentUpdateAction[];
|
|
18
19
|
};
|
|
20
|
+
export type OauthToken = {
|
|
21
|
+
accessToken: string;
|
|
22
|
+
expiresIn: number;
|
|
23
|
+
tokenType: string;
|
|
24
|
+
scope: string;
|
|
25
|
+
refreshToken?: string;
|
|
26
|
+
};
|
|
27
|
+
export interface AuthorizationAPI {
|
|
28
|
+
getToken(): Promise<OauthToken>;
|
|
29
|
+
}
|
|
19
30
|
export interface CartAPI {
|
|
20
31
|
getCartById(id: string): Promise<Cart>;
|
|
21
32
|
addPayment(opts: AddPayment): Promise<Cart>;
|
|
@@ -28,6 +28,15 @@ export type UpdatePayment = {
|
|
|
28
28
|
transaction?: TransactionData;
|
|
29
29
|
paymentMethod?: string;
|
|
30
30
|
};
|
|
31
|
+
export type PaymentModificationValidation = {
|
|
32
|
+
payment: Payment;
|
|
33
|
+
amount: Money;
|
|
34
|
+
type: TransactionType;
|
|
35
|
+
};
|
|
36
|
+
export type PaymentModificationValidationResult = {
|
|
37
|
+
isValid: boolean;
|
|
38
|
+
reason?: string;
|
|
39
|
+
};
|
|
31
40
|
/**
|
|
32
41
|
* Payment service interface exposes methods to interact with the commercetools platform API.
|
|
33
42
|
*/
|
|
@@ -35,4 +44,5 @@ export interface PaymentService {
|
|
|
35
44
|
getPayment(opts: GetPayment): Promise<Payment>;
|
|
36
45
|
createPayment(draft: PaymentDraft): Promise<Payment>;
|
|
37
46
|
updatePayment(opts: UpdatePayment): Promise<Payment>;
|
|
47
|
+
validatePaymentModification(opts: PaymentModificationValidation): PaymentModificationValidationResult;
|
|
38
48
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type Session = {
|
|
2
|
+
id: string;
|
|
3
|
+
version: number;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
lastModifiedAt: string;
|
|
6
|
+
state: 'ACTIVE' | 'EXPIRED';
|
|
7
|
+
activeCart?: {
|
|
8
|
+
cartRef: {
|
|
9
|
+
id: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
customer?: {
|
|
13
|
+
customerRef: {
|
|
14
|
+
externalId?: string;
|
|
15
|
+
id?: string;
|
|
16
|
+
key?: string;
|
|
17
|
+
};
|
|
18
|
+
anonymousId?: string;
|
|
19
|
+
};
|
|
20
|
+
metadata?: {
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export interface SessionService {
|
|
25
|
+
verifySession(sessionId: string): Promise<Session>;
|
|
26
|
+
getCartFromSession(session: Session): string;
|
|
27
|
+
getAllowedPaymentMethodsFromSession(session: Session): string[];
|
|
28
|
+
}
|
package/dist/errorx/errorx.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export declare class MultiErrorx extends Error {
|
|
|
44
44
|
* }
|
|
45
45
|
*/
|
|
46
46
|
export declare class ErrorAuthErrorResponse extends Errorx {
|
|
47
|
-
constructor(additionalOpts?: ErrorxAdditionalOpts);
|
|
47
|
+
constructor(message?: string, additionalOpts?: ErrorxAdditionalOpts, code?: string);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* General (https://docs.commercetools.com/api/errors#general)
|
|
@@ -148,3 +148,6 @@ export declare class ErrorResourceNotFound extends Errorx {
|
|
|
148
148
|
export declare class ErrorConcurrentModification extends Errorx {
|
|
149
149
|
constructor(resourceId: string, expectedVersion: number, currentVersion: number, additionalOpts?: ErrorxAdditionalOpts);
|
|
150
150
|
}
|
|
151
|
+
export declare class ErrorMissingAuthenticationInfo extends Errorx {
|
|
152
|
+
constructor(additionalOpts?: ErrorxAdditionalOpts);
|
|
153
|
+
}
|