@adtrackify/at-service-common 1.0.73 → 1.0.75
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/.editorconfig +12 -12
- package/.vscode/settings.json +9 -9
- package/bitbucket-pipelines.yml +20 -20
- package/build.js +21 -21
- package/dist/index.d.ts +9 -4
- package/dist/index.js +10 -1
- package/dist/index.js.map +2 -2
- package/jest.config.ts +40 -40
- package/package.json +1 -1
- package/src/__tests__/helpers/subscription-helper.spec.ts +40 -40
- package/src/clients/generic/axios.d.ts +7 -7
- package/src/clients/generic/dynamodb-client.ts +113 -113
- package/src/clients/generic/eventbridge-client.ts +52 -52
- package/src/clients/internal-api/destinations-client.ts +58 -58
- package/src/clients/internal-api/index.ts +4 -4
- package/src/clients/internal-api/shopify-app-install-client.ts +59 -59
- package/src/clients/internal-api/users-auth-client.ts +111 -111
- package/src/clients/third-party/shopify-client.ts +12 -1
- package/src/helpers/index.ts +5 -5
- package/src/helpers/input-validation-helper.ts +21 -21
- package/src/helpers/shopify-helper.ts +39 -39
- package/src/helpers/subscription-helper.ts +234 -234
- package/src/index.ts +4 -4
- package/src/libs/index.ts +7 -7
- package/src/libs/url.ts +9 -9
- package/src/services/eventbridge-integration-service.ts +44 -44
- package/src/types/internal-events/event-detail-types.ts +9 -9
- package/tsconfig.json +35 -35
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import log from 'lambda-log';
|
|
2
|
-
import { ApiResponse } from '../../types/api-response';
|
|
3
|
-
import { axiosHttpService } from '../generic/http-client';
|
|
4
|
-
import { ShopifyAppInstall, ShopifyAppSubscriptionStatus } from '@adtrackify/at-tracking-event-types';
|
|
5
|
-
//const BASE_API_URL = process.env.BASE_API_URL;
|
|
6
|
-
//const DESTINATIONS_API_KEY = process.env.DESTINATIONS_API_KEY;
|
|
7
|
-
|
|
8
|
-
export interface ShopifyAppInstallResponseData {
|
|
9
|
-
shopifyAppInstall: ShopifyAppInstall;
|
|
10
|
-
[ key: string ]: any;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface UpdateShopifyAppInstallRequest {
|
|
14
|
-
appSubscriptionStatus?: ShopifyAppSubscriptionStatus,
|
|
15
|
-
pixelId?: string,
|
|
16
|
-
shopifyAppInstallId: string;
|
|
17
|
-
isAppEnabled?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class ShopifyAppInstallClient {
|
|
21
|
-
|
|
22
|
-
public BASE_API_URL: string;
|
|
23
|
-
public SHOPIFY_APP_INSTALL_API_KEY: string;
|
|
24
|
-
|
|
25
|
-
constructor (baseApiUrl: string, shopifyAppInstallApiKey: string) {
|
|
26
|
-
this.BASE_API_URL = baseApiUrl;
|
|
27
|
-
this.SHOPIFY_APP_INSTALL_API_KEY = shopifyAppInstallApiKey;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
getConfig = () => {
|
|
31
|
-
const SERVICE_API_ROOT_URL = `${this.BASE_API_URL}/shopify-app-installs`;
|
|
32
|
-
return {
|
|
33
|
-
baseURL: SERVICE_API_ROOT_URL,
|
|
34
|
-
headers: {
|
|
35
|
-
common: {
|
|
36
|
-
'x-api-key': this.SHOPIFY_APP_INSTALL_API_KEY
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
getClient = async () => {
|
|
43
|
-
return axiosHttpService(this.getConfig());
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
updateShopifyAppInstall = async (shopifyAppInstallId: string, updateShopifyAppInstallRequest: UpdateShopifyAppInstallRequest): Promise<ApiResponse<ShopifyAppInstallResponseData>> => {
|
|
47
|
-
const client = await this.getClient();
|
|
48
|
-
const response = await client.put(`/${shopifyAppInstallId}`, updateShopifyAppInstallRequest);
|
|
49
|
-
log.info('updateShopifyAppInstall', { response });
|
|
50
|
-
return response as ApiResponse<ShopifyAppInstallResponseData>;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
getShopifyAppInstall = async (shopifyAppInstallId: string): Promise<ApiResponse<ShopifyAppInstallResponseData>> => {
|
|
54
|
-
const client = await this.getClient();
|
|
55
|
-
const response = await client.get(`/${shopifyAppInstallId}`);
|
|
56
|
-
log.info('getShopifyAppInstall', { response });
|
|
57
|
-
return response as ApiResponse<ShopifyAppInstallResponseData>;
|
|
58
|
-
};
|
|
59
|
-
}
|
|
1
|
+
import log from 'lambda-log';
|
|
2
|
+
import { ApiResponse } from '../../types/api-response';
|
|
3
|
+
import { axiosHttpService } from '../generic/http-client';
|
|
4
|
+
import { ShopifyAppInstall, ShopifyAppSubscriptionStatus } from '@adtrackify/at-tracking-event-types';
|
|
5
|
+
//const BASE_API_URL = process.env.BASE_API_URL;
|
|
6
|
+
//const DESTINATIONS_API_KEY = process.env.DESTINATIONS_API_KEY;
|
|
7
|
+
|
|
8
|
+
export interface ShopifyAppInstallResponseData {
|
|
9
|
+
shopifyAppInstall: ShopifyAppInstall;
|
|
10
|
+
[ key: string ]: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UpdateShopifyAppInstallRequest {
|
|
14
|
+
appSubscriptionStatus?: ShopifyAppSubscriptionStatus,
|
|
15
|
+
pixelId?: string,
|
|
16
|
+
shopifyAppInstallId: string;
|
|
17
|
+
isAppEnabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class ShopifyAppInstallClient {
|
|
21
|
+
|
|
22
|
+
public BASE_API_URL: string;
|
|
23
|
+
public SHOPIFY_APP_INSTALL_API_KEY: string;
|
|
24
|
+
|
|
25
|
+
constructor (baseApiUrl: string, shopifyAppInstallApiKey: string) {
|
|
26
|
+
this.BASE_API_URL = baseApiUrl;
|
|
27
|
+
this.SHOPIFY_APP_INSTALL_API_KEY = shopifyAppInstallApiKey;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getConfig = () => {
|
|
31
|
+
const SERVICE_API_ROOT_URL = `${this.BASE_API_URL}/shopify-app-installs`;
|
|
32
|
+
return {
|
|
33
|
+
baseURL: SERVICE_API_ROOT_URL,
|
|
34
|
+
headers: {
|
|
35
|
+
common: {
|
|
36
|
+
'x-api-key': this.SHOPIFY_APP_INSTALL_API_KEY
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
getClient = async () => {
|
|
43
|
+
return axiosHttpService(this.getConfig());
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
updateShopifyAppInstall = async (shopifyAppInstallId: string, updateShopifyAppInstallRequest: UpdateShopifyAppInstallRequest): Promise<ApiResponse<ShopifyAppInstallResponseData>> => {
|
|
47
|
+
const client = await this.getClient();
|
|
48
|
+
const response = await client.put(`/${shopifyAppInstallId}`, updateShopifyAppInstallRequest);
|
|
49
|
+
log.info('updateShopifyAppInstall', { response });
|
|
50
|
+
return response as ApiResponse<ShopifyAppInstallResponseData>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
getShopifyAppInstall = async (shopifyAppInstallId: string): Promise<ApiResponse<ShopifyAppInstallResponseData>> => {
|
|
54
|
+
const client = await this.getClient();
|
|
55
|
+
const response = await client.get(`/${shopifyAppInstallId}`);
|
|
56
|
+
log.info('getShopifyAppInstall', { response });
|
|
57
|
+
return response as ApiResponse<ShopifyAppInstallResponseData>;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
import { User } from '@adtrackify/at-tracking-event-types';
|
|
2
|
-
import * as log from 'lambda-log';
|
|
3
|
-
import { HttpError, HttpStatusCodes } from '../../libs';
|
|
4
|
-
import { ApiResponse } from '../../types/api-response';
|
|
5
|
-
import { axiosHttpService } from '../generic/http-client';
|
|
6
|
-
|
|
7
|
-
export interface UserResponseData {
|
|
8
|
-
user: User;
|
|
9
|
-
[ key: string ]: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface UserSignupRequest {
|
|
13
|
-
email: string,
|
|
14
|
-
password: string,
|
|
15
|
-
givenName: string,
|
|
16
|
-
familyName: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class UsersAuthClient {
|
|
20
|
-
|
|
21
|
-
public SERVICE_API_ROOT_URL: string;
|
|
22
|
-
public BASE_API_URL: string;
|
|
23
|
-
public USERS_AUTH_API_KEY: string;
|
|
24
|
-
constructor (baseApiUrl: string, usersAuthApiKey?: string) {
|
|
25
|
-
this.BASE_API_URL = baseApiUrl;
|
|
26
|
-
this.USERS_AUTH_API_KEY = usersAuthApiKey as string;
|
|
27
|
-
this.SERVICE_API_ROOT_URL = `${this.BASE_API_URL}/auth`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
getConfig = () => {
|
|
31
|
-
return {
|
|
32
|
-
baseURL: this.SERVICE_API_ROOT_URL,
|
|
33
|
-
headers: {
|
|
34
|
-
common: {
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
getClient = async () => {
|
|
41
|
-
return axiosHttpService(this.getConfig());
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
signupAndConfirmUser = async (userSignupRequest: any): Promise<any> => {
|
|
45
|
-
const user = await this.signupUser(userSignupRequest);
|
|
46
|
-
await this.adminConfirmUser(user.email);
|
|
47
|
-
// if fail - delete user and throw error
|
|
48
|
-
return user;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
signupUser = async (userSignupRequest: UserSignupRequest): Promise<any> => {
|
|
52
|
-
log.info('Attempting to signup user', { email: userSignupRequest.email });
|
|
53
|
-
|
|
54
|
-
const client = await this.getClient();
|
|
55
|
-
const response = await client.post('/signup', userSignupRequest);
|
|
56
|
-
|
|
57
|
-
// Check if Successful or throw error
|
|
58
|
-
if (response.status !== 200 || !response?.data?.user) {
|
|
59
|
-
const message = 'User Signup Failed';
|
|
60
|
-
log.error(message, { response });
|
|
61
|
-
throw new HttpError(HttpStatusCodes.INTERNAL_SERVER_ERROR, message);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
log.info('User Signup Successful', { response });
|
|
65
|
-
return response.data.user;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
//userName is same as user id
|
|
69
|
-
adminConfirmUser = async (email: string) => {
|
|
70
|
-
//confirm user
|
|
71
|
-
//@TODO update user auth service with admin confirm user endpoint
|
|
72
|
-
log.info('Attempting to admin confirm user', { email });
|
|
73
|
-
|
|
74
|
-
const client = await this.getClient();
|
|
75
|
-
const response = await client.post('/admin/confirm',
|
|
76
|
-
{
|
|
77
|
-
email
|
|
78
|
-
}, {
|
|
79
|
-
headers: {
|
|
80
|
-
'x-api-key': this.USERS_AUTH_API_KEY
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// Check if Successful or throw error
|
|
86
|
-
if (response.status !== 200) {
|
|
87
|
-
const message = 'Admin User Confirmation Failed';
|
|
88
|
-
log.error(message, { response });
|
|
89
|
-
throw new HttpError(HttpStatusCodes.INTERNAL_SERVER_ERROR, message);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
log.info('Admin User Confirmation Successful', { response });
|
|
93
|
-
return response.data.user;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
getUserByEmail = async (email: string): Promise<ApiResponse<UserResponseData>> => {
|
|
97
|
-
const client = await this.getClient();
|
|
98
|
-
const getUserResponse = await client.get('/lookup', {
|
|
99
|
-
headers: {
|
|
100
|
-
'x-api-key': this.USERS_AUTH_API_KEY
|
|
101
|
-
},
|
|
102
|
-
params: {
|
|
103
|
-
email
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
log.info('getUserResponse', { getUserResponse });
|
|
107
|
-
return getUserResponse;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
1
|
+
import { User } from '@adtrackify/at-tracking-event-types';
|
|
2
|
+
import * as log from 'lambda-log';
|
|
3
|
+
import { HttpError, HttpStatusCodes } from '../../libs';
|
|
4
|
+
import { ApiResponse } from '../../types/api-response';
|
|
5
|
+
import { axiosHttpService } from '../generic/http-client';
|
|
6
|
+
|
|
7
|
+
export interface UserResponseData {
|
|
8
|
+
user: User;
|
|
9
|
+
[ key: string ]: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UserSignupRequest {
|
|
13
|
+
email: string,
|
|
14
|
+
password: string,
|
|
15
|
+
givenName: string,
|
|
16
|
+
familyName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class UsersAuthClient {
|
|
20
|
+
|
|
21
|
+
public SERVICE_API_ROOT_URL: string;
|
|
22
|
+
public BASE_API_URL: string;
|
|
23
|
+
public USERS_AUTH_API_KEY: string;
|
|
24
|
+
constructor (baseApiUrl: string, usersAuthApiKey?: string) {
|
|
25
|
+
this.BASE_API_URL = baseApiUrl;
|
|
26
|
+
this.USERS_AUTH_API_KEY = usersAuthApiKey as string;
|
|
27
|
+
this.SERVICE_API_ROOT_URL = `${this.BASE_API_URL}/auth`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getConfig = () => {
|
|
31
|
+
return {
|
|
32
|
+
baseURL: this.SERVICE_API_ROOT_URL,
|
|
33
|
+
headers: {
|
|
34
|
+
common: {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
getClient = async () => {
|
|
41
|
+
return axiosHttpService(this.getConfig());
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
signupAndConfirmUser = async (userSignupRequest: any): Promise<any> => {
|
|
45
|
+
const user = await this.signupUser(userSignupRequest);
|
|
46
|
+
await this.adminConfirmUser(user.email);
|
|
47
|
+
// if fail - delete user and throw error
|
|
48
|
+
return user;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
signupUser = async (userSignupRequest: UserSignupRequest): Promise<any> => {
|
|
52
|
+
log.info('Attempting to signup user', { email: userSignupRequest.email });
|
|
53
|
+
|
|
54
|
+
const client = await this.getClient();
|
|
55
|
+
const response = await client.post('/signup', userSignupRequest);
|
|
56
|
+
|
|
57
|
+
// Check if Successful or throw error
|
|
58
|
+
if (response.status !== 200 || !response?.data?.user) {
|
|
59
|
+
const message = 'User Signup Failed';
|
|
60
|
+
log.error(message, { response });
|
|
61
|
+
throw new HttpError(HttpStatusCodes.INTERNAL_SERVER_ERROR, message);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
log.info('User Signup Successful', { response });
|
|
65
|
+
return response.data.user;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
//userName is same as user id
|
|
69
|
+
adminConfirmUser = async (email: string) => {
|
|
70
|
+
//confirm user
|
|
71
|
+
//@TODO update user auth service with admin confirm user endpoint
|
|
72
|
+
log.info('Attempting to admin confirm user', { email });
|
|
73
|
+
|
|
74
|
+
const client = await this.getClient();
|
|
75
|
+
const response = await client.post('/admin/confirm',
|
|
76
|
+
{
|
|
77
|
+
email
|
|
78
|
+
}, {
|
|
79
|
+
headers: {
|
|
80
|
+
'x-api-key': this.USERS_AUTH_API_KEY
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Check if Successful or throw error
|
|
86
|
+
if (response.status !== 200) {
|
|
87
|
+
const message = 'Admin User Confirmation Failed';
|
|
88
|
+
log.error(message, { response });
|
|
89
|
+
throw new HttpError(HttpStatusCodes.INTERNAL_SERVER_ERROR, message);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
log.info('Admin User Confirmation Successful', { response });
|
|
93
|
+
return response.data.user;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
getUserByEmail = async (email: string): Promise<ApiResponse<UserResponseData>> => {
|
|
97
|
+
const client = await this.getClient();
|
|
98
|
+
const getUserResponse = await client.get('/lookup', {
|
|
99
|
+
headers: {
|
|
100
|
+
'x-api-key': this.USERS_AUTH_API_KEY
|
|
101
|
+
},
|
|
102
|
+
params: {
|
|
103
|
+
email
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
log.info('getUserResponse', { getUserResponse });
|
|
107
|
+
return getUserResponse;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
|
|
@@ -64,7 +64,7 @@ export class ShopifyClient {
|
|
|
64
64
|
const res = await this.genericShopifyPost(url, accessToken, payload);
|
|
65
65
|
|
|
66
66
|
if (res.status >= 400) {
|
|
67
|
-
log.error('Failed to
|
|
67
|
+
log.error('Failed to update Shopify app Metafield ', { shop, accessToken, url, payload });
|
|
68
68
|
}
|
|
69
69
|
return res;
|
|
70
70
|
};
|
|
@@ -96,6 +96,17 @@ export class ShopifyClient {
|
|
|
96
96
|
return res;
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
+
static cancelAppSubscription = async (shop: string, accessToken: string, chargeId: string) => {
|
|
100
|
+
const url = `https://${shop}/admin/api/${this._shopify_api_version}/recurring_application_charges/${chargeId}.json`;
|
|
101
|
+
const client = axiosHttpService();
|
|
102
|
+
const res = await client.delete(url, { headers: { 'X-Shopify-Access-Token': accessToken } });
|
|
103
|
+
|
|
104
|
+
if (res.status !== 200) {
|
|
105
|
+
log.error('Failed to cancel recurring App billing', { shop, accessToken, url });
|
|
106
|
+
}
|
|
107
|
+
return res;
|
|
108
|
+
};
|
|
109
|
+
|
|
99
110
|
static listAppSubscriptions = async (shop: string, accessToken: string) => {
|
|
100
111
|
const url = `https://${shop}/admin/api/${this._shopify_api_version}/recurring_application_charges.json`;
|
|
101
112
|
const res = await this.genericShopifyGet(url, accessToken);
|
package/src/helpers/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './input-validation-helper';
|
|
2
|
-
export * from './logging-helper';
|
|
3
|
-
export * from './response-helper';
|
|
4
|
-
export * from './shopify-helper';
|
|
5
|
-
export * from './subscription-helper';
|
|
1
|
+
export * from './input-validation-helper';
|
|
2
|
+
export * from './logging-helper';
|
|
3
|
+
export * from './response-helper';
|
|
4
|
+
export * from './shopify-helper';
|
|
5
|
+
export * from './subscription-helper';
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import Joi from 'joi';
|
|
2
|
-
import * as log from 'lambda-log';
|
|
3
|
-
import { HttpError } from '../libs/http-error';
|
|
4
|
-
|
|
5
|
-
export const validateInput = (schema: Joi.ObjectSchema<any>, input: any) => {
|
|
6
|
-
const { error, value } = schema.validate(input);
|
|
7
|
-
if (error) {
|
|
8
|
-
log.info('', { error });
|
|
9
|
-
|
|
10
|
-
const httperr = HttpError.badRequest('Bad Request', {
|
|
11
|
-
errors: error.details.map(detail => ({
|
|
12
|
-
message: detail?.message,
|
|
13
|
-
key: detail?.context?.key,
|
|
14
|
-
path: detail?.path,
|
|
15
|
-
}))
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
log.info('', { httperr });
|
|
19
|
-
throw httperr;
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
1
|
+
import Joi from 'joi';
|
|
2
|
+
import * as log from 'lambda-log';
|
|
3
|
+
import { HttpError } from '../libs/http-error';
|
|
4
|
+
|
|
5
|
+
export const validateInput = (schema: Joi.ObjectSchema<any>, input: any) => {
|
|
6
|
+
const { error, value } = schema.validate(input);
|
|
7
|
+
if (error) {
|
|
8
|
+
log.info('', { error });
|
|
9
|
+
|
|
10
|
+
const httperr = HttpError.badRequest('Bad Request', {
|
|
11
|
+
errors: error.details.map(detail => ({
|
|
12
|
+
message: detail?.message,
|
|
13
|
+
key: detail?.context?.key,
|
|
14
|
+
path: detail?.path,
|
|
15
|
+
}))
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
log.info('', { httperr });
|
|
19
|
+
throw httperr;
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
22
|
};
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { createHmac } from 'crypto';
|
|
2
|
-
import * as log from 'lambda-log';
|
|
3
|
-
import { HttpError } from '../libs';
|
|
4
|
-
import { mapObjectToQueryString } from '../libs/url';
|
|
5
|
-
export interface ShopifyRequestValidationParameters {
|
|
6
|
-
code: string,
|
|
7
|
-
hmac?: string,
|
|
8
|
-
shop: string,
|
|
9
|
-
state: string,
|
|
10
|
-
timestamp: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const isShopifyRequestValid = (validationParams: ShopifyRequestValidationParameters, validationHmac: string, shopifyAppApiSecret: string): boolean => {
|
|
14
|
-
// remove hmac if it exists
|
|
15
|
-
// map input to query string
|
|
16
|
-
// generate hash using api secret key and validate it matches hmac
|
|
17
|
-
delete validationParams.hmac;
|
|
18
|
-
const hmacString = mapObjectToQueryString(validationParams);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const generatedHash = createHmac('sha256', shopifyAppApiSecret)
|
|
22
|
-
.update(hmacString)
|
|
23
|
-
.digest('hex');
|
|
24
|
-
|
|
25
|
-
return generatedHash === validationHmac;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const validateShopifyRequest = (validationParams: ShopifyRequestValidationParameters, validationHmac: string, shopifyAppApiSecret: string) => {
|
|
29
|
-
log.info('Validating shopify request is authentic', { validationParams });
|
|
30
|
-
const isValid = isShopifyRequestValid(validationParams, validationHmac as string, shopifyAppApiSecret);
|
|
31
|
-
if (!isValid) {
|
|
32
|
-
const message = 'Failed: Shopify Request hmac validation';
|
|
33
|
-
log.error(message);
|
|
34
|
-
throw HttpError.badRequest(message);
|
|
35
|
-
}
|
|
36
|
-
log.info('Sucess: Shopify Request hmac validation');
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
|
|
1
|
+
import { createHmac } from 'crypto';
|
|
2
|
+
import * as log from 'lambda-log';
|
|
3
|
+
import { HttpError } from '../libs';
|
|
4
|
+
import { mapObjectToQueryString } from '../libs/url';
|
|
5
|
+
export interface ShopifyRequestValidationParameters {
|
|
6
|
+
code: string,
|
|
7
|
+
hmac?: string,
|
|
8
|
+
shop: string,
|
|
9
|
+
state: string,
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const isShopifyRequestValid = (validationParams: ShopifyRequestValidationParameters, validationHmac: string, shopifyAppApiSecret: string): boolean => {
|
|
14
|
+
// remove hmac if it exists
|
|
15
|
+
// map input to query string
|
|
16
|
+
// generate hash using api secret key and validate it matches hmac
|
|
17
|
+
delete validationParams.hmac;
|
|
18
|
+
const hmacString = mapObjectToQueryString(validationParams);
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const generatedHash = createHmac('sha256', shopifyAppApiSecret)
|
|
22
|
+
.update(hmacString)
|
|
23
|
+
.digest('hex');
|
|
24
|
+
|
|
25
|
+
return generatedHash === validationHmac;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const validateShopifyRequest = (validationParams: ShopifyRequestValidationParameters, validationHmac: string, shopifyAppApiSecret: string) => {
|
|
29
|
+
log.info('Validating shopify request is authentic', { validationParams });
|
|
30
|
+
const isValid = isShopifyRequestValid(validationParams, validationHmac as string, shopifyAppApiSecret);
|
|
31
|
+
if (!isValid) {
|
|
32
|
+
const message = 'Failed: Shopify Request hmac validation';
|
|
33
|
+
log.error(message);
|
|
34
|
+
throw HttpError.badRequest(message);
|
|
35
|
+
}
|
|
36
|
+
log.info('Sucess: Shopify Request hmac validation');
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|