@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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@labdigital/commercetools-mock",
|
|
3
3
|
"author": "Michael van Tellingen",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"body-parser": "^1.20.2",
|
|
38
38
|
"deep-equal": "^2.2.2",
|
|
39
39
|
"express": "^4.18.2",
|
|
40
|
+
"light-my-request": "^5.11.0",
|
|
40
41
|
"lodash.isequal": "^4.5.0",
|
|
41
42
|
"morgan": "^1.10.0",
|
|
42
43
|
"msw": "^2.0.0",
|
|
43
|
-
"supertest": "^6.3.3",
|
|
44
44
|
"uuid": "^9.0.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"got": "^11.8.3",
|
|
68
68
|
"husky": "^8.0.3",
|
|
69
69
|
"prettier": "^3.0.0",
|
|
70
|
+
"supertest": "^6.3.3",
|
|
70
71
|
"timekeeper": "^2.3.1",
|
|
71
72
|
"ts-node": "^10.9.1",
|
|
72
73
|
"tslib": "^2.6.1",
|
package/src/ctMock.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import express, { NextFunction, Request, Response } from 'express'
|
|
2
|
-
import supertest from 'supertest'
|
|
3
2
|
import morgan from 'morgan'
|
|
3
|
+
import inject from 'light-my-request'
|
|
4
4
|
import { setupServer, SetupServer } from 'msw/node'
|
|
5
5
|
import { http, HttpResponse } from 'msw'
|
|
6
6
|
import { AbstractStorage, InMemoryStorage } from './storage/index.js'
|
|
@@ -16,6 +16,7 @@ import { ProjectService } from './services/project.js'
|
|
|
16
16
|
import { createRepositories, RepositoryMap } from './repositories/index.js'
|
|
17
17
|
import { createServices } from './services/index.js'
|
|
18
18
|
import { ProjectRepository } from './repositories/project.js'
|
|
19
|
+
import { mapHeaderType } from './helpers.js'
|
|
19
20
|
|
|
20
21
|
export type CommercetoolsMockOptions = {
|
|
21
22
|
validateCredentials: boolean
|
|
@@ -106,6 +107,7 @@ export class CommercetoolsMock {
|
|
|
106
107
|
|
|
107
108
|
private createApp(options?: AppOptions): express.Express {
|
|
108
109
|
this._repositories = createRepositories(this._storage)
|
|
110
|
+
this._oauth2.setCustomerRepository(this._repositories.customer)
|
|
109
111
|
|
|
110
112
|
const app = express()
|
|
111
113
|
|
|
@@ -139,6 +141,14 @@ export class CommercetoolsMock {
|
|
|
139
141
|
|
|
140
142
|
app.use((err: Error, req: Request, resp: Response, next: NextFunction) => {
|
|
141
143
|
if (err instanceof CommercetoolsError) {
|
|
144
|
+
if (err.errors?.length > 0) {
|
|
145
|
+
return resp.status(err.statusCode).send({
|
|
146
|
+
statusCode: err.statusCode,
|
|
147
|
+
message: err.message,
|
|
148
|
+
errors: err.errors,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
142
152
|
return resp.status(err.statusCode).send({
|
|
143
153
|
statusCode: err.statusCode,
|
|
144
154
|
message: err.message,
|
|
@@ -166,56 +176,66 @@ export class CommercetoolsMock {
|
|
|
166
176
|
}
|
|
167
177
|
}
|
|
168
178
|
|
|
169
|
-
const
|
|
179
|
+
const server = this.app
|
|
170
180
|
this._mswServer = setupServer(
|
|
171
181
|
http.post(`${this.options.authHost}/oauth/*`, async ({ request }) => {
|
|
172
|
-
const
|
|
182
|
+
const body = await request.text()
|
|
173
183
|
const url = new URL(request.url)
|
|
174
|
-
const
|
|
175
|
-
.post(url.pathname + '?' + url.searchParams.toString())
|
|
176
|
-
.set(copyHeaders(request.headers))
|
|
177
|
-
.send(text)
|
|
184
|
+
const headers = copyHeaders(request.headers)
|
|
178
185
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
186
|
+
const res = await inject(server)
|
|
187
|
+
.post(url.pathname + '?' + url.searchParams.toString())
|
|
188
|
+
.body(body)
|
|
189
|
+
.headers(headers)
|
|
190
|
+
.end()
|
|
191
|
+
return new HttpResponse(res.body, {
|
|
192
|
+
status: res.statusCode,
|
|
193
|
+
headers: mapHeaderType(res.headers),
|
|
182
194
|
})
|
|
183
195
|
}),
|
|
184
196
|
http.get(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
185
197
|
const body = await request.text()
|
|
186
198
|
const url = new URL(request.url)
|
|
187
|
-
const
|
|
199
|
+
const headers = copyHeaders(request.headers)
|
|
200
|
+
|
|
201
|
+
const res = await inject(server)
|
|
188
202
|
.get(url.pathname + '?' + url.searchParams.toString())
|
|
189
|
-
.
|
|
190
|
-
.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
203
|
+
.body(body)
|
|
204
|
+
.headers(headers)
|
|
205
|
+
.end()
|
|
206
|
+
return new HttpResponse(res.body, {
|
|
207
|
+
status: res.statusCode,
|
|
208
|
+
headers: mapHeaderType(res.headers),
|
|
194
209
|
})
|
|
195
210
|
}),
|
|
196
211
|
http.post(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
197
212
|
const body = await request.text()
|
|
198
213
|
const url = new URL(request.url)
|
|
199
|
-
const
|
|
214
|
+
const headers = copyHeaders(request.headers)
|
|
215
|
+
|
|
216
|
+
const res = await inject(server)
|
|
200
217
|
.post(url.pathname + '?' + url.searchParams.toString())
|
|
201
|
-
.
|
|
202
|
-
.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
218
|
+
.body(body)
|
|
219
|
+
.headers(headers)
|
|
220
|
+
.end()
|
|
221
|
+
return new HttpResponse(res.body, {
|
|
222
|
+
status: res.statusCode,
|
|
223
|
+
headers: mapHeaderType(res.headers),
|
|
206
224
|
})
|
|
207
225
|
}),
|
|
208
226
|
http.delete(`${this.options.apiHost}/*`, async ({ request }) => {
|
|
209
227
|
const body = await request.text()
|
|
210
228
|
const url = new URL(request.url)
|
|
211
|
-
const
|
|
212
|
-
.delete(url.pathname + '?' + url.searchParams.toString())
|
|
213
|
-
.set(copyHeaders(request.headers))
|
|
214
|
-
.send(body)
|
|
229
|
+
const headers = copyHeaders(request.headers)
|
|
215
230
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
231
|
+
const res = await inject(server)
|
|
232
|
+
.delete(url.pathname + '?' + url.searchParams.toString())
|
|
233
|
+
.body(body)
|
|
234
|
+
.headers(headers)
|
|
235
|
+
.end()
|
|
236
|
+
return new HttpResponse(res.body, {
|
|
237
|
+
status: res.statusCode,
|
|
238
|
+
headers: mapHeaderType(res.headers),
|
|
219
239
|
})
|
|
220
240
|
})
|
|
221
241
|
)
|
package/src/exceptions.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
export abstract class BaseError {
|
|
2
2
|
abstract message: string
|
|
3
|
+
abstract errors?: BaseError[]
|
|
3
4
|
}
|
|
4
5
|
|
|
5
6
|
export class CommercetoolsError<T extends BaseError> extends Error {
|
|
6
7
|
info: T
|
|
7
8
|
statusCode: number
|
|
8
9
|
|
|
10
|
+
errors: BaseError[]
|
|
11
|
+
|
|
9
12
|
constructor(info: T, statusCode = 400) {
|
|
10
13
|
super(info.message)
|
|
11
14
|
this.info = info
|
|
12
15
|
this.statusCode = statusCode || 500
|
|
16
|
+
this.errors = info.errors ?? []
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
19
|
|
package/src/helpers.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OutgoingHttpHeaders } from 'node:http'
|
|
1
2
|
import { ParsedQs } from 'qs'
|
|
2
3
|
import { v4 as uuidv4 } from 'uuid'
|
|
3
4
|
|
|
@@ -59,3 +60,20 @@ export const queryParamsValue = (
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export const cloneObject = <T>(o: T): T => JSON.parse(JSON.stringify(o))
|
|
63
|
+
|
|
64
|
+
export const mapHeaderType = (
|
|
65
|
+
outgoingHttpHeaders: OutgoingHttpHeaders
|
|
66
|
+
): HeadersInit => {
|
|
67
|
+
const headersInit: HeadersInit = {}
|
|
68
|
+
for (const key in outgoingHttpHeaders) {
|
|
69
|
+
const value = outgoingHttpHeaders[key]
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
|
+
// Join multiple values for the same header with a comma
|
|
72
|
+
headersInit[key] = value.join(', ')
|
|
73
|
+
} else if (value !== undefined) {
|
|
74
|
+
// Single value or undefined
|
|
75
|
+
headersInit[key] = value.toString()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return headersInit
|
|
79
|
+
}
|
package/src/oauth/server.ts
CHANGED
|
@@ -10,18 +10,45 @@ import { CommercetoolsError, InvalidRequestError } from '../exceptions.js'
|
|
|
10
10
|
import { InvalidClientError, UnsupportedGrantType } from './errors.js'
|
|
11
11
|
import { OAuth2Store } from './store.js'
|
|
12
12
|
import { getBearerToken } from './helpers.js'
|
|
13
|
+
import { CustomerRepository } from '../repositories/customer.js'
|
|
14
|
+
import { hashPassword } from '../lib/password.js'
|
|
15
|
+
|
|
16
|
+
type AuthRequest = Request & {
|
|
17
|
+
credentials: {
|
|
18
|
+
clientId: string
|
|
19
|
+
clientSecret: string
|
|
20
|
+
}
|
|
21
|
+
}
|
|
13
22
|
|
|
14
23
|
export class OAuth2Server {
|
|
15
24
|
store: OAuth2Store
|
|
25
|
+
private customerRepository: CustomerRepository
|
|
16
26
|
|
|
17
27
|
constructor(options: { enabled: boolean; validate: boolean }) {
|
|
18
28
|
this.store = new OAuth2Store(options.validate)
|
|
19
29
|
}
|
|
20
30
|
|
|
31
|
+
setCustomerRepository(repository: CustomerRepository) {
|
|
32
|
+
this.customerRepository = repository
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
createRouter() {
|
|
22
36
|
const router = express.Router()
|
|
23
37
|
router.use(bodyParser.urlencoded({ extended: true }))
|
|
38
|
+
router.use(this.validateClientCredentials.bind(this))
|
|
24
39
|
router.post('/token', this.tokenHandler.bind(this))
|
|
40
|
+
router.post(
|
|
41
|
+
'/:projectKey/customers/token',
|
|
42
|
+
this.customerTokenHandler.bind(this)
|
|
43
|
+
)
|
|
44
|
+
router.post(
|
|
45
|
+
'/:projectKey/in-store/key=:storeKey/customers/token',
|
|
46
|
+
this.inStoreCustomerTokenHandler.bind(this)
|
|
47
|
+
)
|
|
48
|
+
router.post(
|
|
49
|
+
'/:projectKey/anonymous/token',
|
|
50
|
+
this.anonymousTokenHandler.bind(this)
|
|
51
|
+
)
|
|
25
52
|
return router
|
|
26
53
|
}
|
|
27
54
|
|
|
@@ -56,7 +83,12 @@ export class OAuth2Server {
|
|
|
56
83
|
next()
|
|
57
84
|
}
|
|
58
85
|
}
|
|
59
|
-
|
|
86
|
+
|
|
87
|
+
async validateClientCredentials(
|
|
88
|
+
request: AuthRequest,
|
|
89
|
+
response: Response,
|
|
90
|
+
next: NextFunction
|
|
91
|
+
) {
|
|
60
92
|
const authHeader = request.header('Authorization')
|
|
61
93
|
if (!authHeader) {
|
|
62
94
|
return next(
|
|
@@ -84,6 +116,19 @@ export class OAuth2Server {
|
|
|
84
116
|
)
|
|
85
117
|
}
|
|
86
118
|
|
|
119
|
+
request.credentials = {
|
|
120
|
+
clientId: credentials.name,
|
|
121
|
+
clientSecret: credentials.pass,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
next()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async tokenHandler(
|
|
128
|
+
request: AuthRequest,
|
|
129
|
+
response: Response,
|
|
130
|
+
next: NextFunction
|
|
131
|
+
) {
|
|
87
132
|
const grantType = request.query.grant_type || request.body.grant_type
|
|
88
133
|
if (!grantType) {
|
|
89
134
|
return next(
|
|
@@ -99,8 +144,15 @@ export class OAuth2Server {
|
|
|
99
144
|
|
|
100
145
|
if (grantType === 'client_credentials') {
|
|
101
146
|
const token = this.store.getClientToken(
|
|
102
|
-
credentials.
|
|
103
|
-
credentials.
|
|
147
|
+
request.credentials.clientId,
|
|
148
|
+
request.credentials.clientSecret,
|
|
149
|
+
request.query.scope?.toString()
|
|
150
|
+
)
|
|
151
|
+
return response.status(200).send(token)
|
|
152
|
+
} else if (grantType === 'refresh_token') {
|
|
153
|
+
const token = this.store.getClientToken(
|
|
154
|
+
request.credentials.clientId,
|
|
155
|
+
request.credentials.clientSecret,
|
|
104
156
|
request.query.scope?.toString()
|
|
105
157
|
)
|
|
106
158
|
return response.status(200).send(token)
|
|
@@ -116,4 +168,86 @@ export class OAuth2Server {
|
|
|
116
168
|
)
|
|
117
169
|
}
|
|
118
170
|
}
|
|
171
|
+
async customerTokenHandler(
|
|
172
|
+
request: AuthRequest,
|
|
173
|
+
response: Response,
|
|
174
|
+
next: NextFunction
|
|
175
|
+
) {
|
|
176
|
+
const grantType = request.query.grant_type || request.body.grant_type
|
|
177
|
+
if (!grantType) {
|
|
178
|
+
return next(
|
|
179
|
+
new CommercetoolsError<InvalidRequestError>(
|
|
180
|
+
{
|
|
181
|
+
code: 'invalid_request',
|
|
182
|
+
message: 'Missing required parameter: grant_type.',
|
|
183
|
+
},
|
|
184
|
+
400
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (grantType === 'password') {
|
|
190
|
+
const username = request.query.username || request.body.username
|
|
191
|
+
const password = hashPassword(
|
|
192
|
+
request.query.password || request.body.password
|
|
193
|
+
)
|
|
194
|
+
const scope =
|
|
195
|
+
request.query.scope?.toString() || request.body.scope?.toString()
|
|
196
|
+
|
|
197
|
+
const result = this.customerRepository.query(
|
|
198
|
+
{ projectKey: request.params.projectKey },
|
|
199
|
+
{
|
|
200
|
+
where: [`email = "${username}"`, `password = "${password}"`],
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
if (result.count === 0) {
|
|
205
|
+
return next(
|
|
206
|
+
new CommercetoolsError<any>(
|
|
207
|
+
{
|
|
208
|
+
code: 'invalid_customer_account_credentials',
|
|
209
|
+
message: 'Customer account with the given credentials not found.',
|
|
210
|
+
},
|
|
211
|
+
400
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const customer = result.results[0]
|
|
217
|
+
const token = this.store.getCustomerToken(scope, customer.id)
|
|
218
|
+
return response.status(200).send(token)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async inStoreCustomerTokenHandler(
|
|
223
|
+
request: Request,
|
|
224
|
+
response: Response,
|
|
225
|
+
next: NextFunction
|
|
226
|
+
) {
|
|
227
|
+
return next(
|
|
228
|
+
new CommercetoolsError<InvalidClientError>(
|
|
229
|
+
{
|
|
230
|
+
code: 'invalid_client',
|
|
231
|
+
message: 'Not implemented yet in commercetools-mock',
|
|
232
|
+
},
|
|
233
|
+
401
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async anonymousTokenHandler(
|
|
239
|
+
request: Request,
|
|
240
|
+
response: Response,
|
|
241
|
+
next: NextFunction
|
|
242
|
+
) {
|
|
243
|
+
return next(
|
|
244
|
+
new CommercetoolsError<InvalidClientError>(
|
|
245
|
+
{
|
|
246
|
+
code: 'invalid_client',
|
|
247
|
+
message: 'Not implemented yet in commercetools-mock',
|
|
248
|
+
},
|
|
249
|
+
401
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
}
|
|
119
253
|
}
|
package/src/oauth/store.ts
CHANGED
|
@@ -26,6 +26,19 @@ export class OAuth2Store {
|
|
|
26
26
|
return token
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
getCustomerToken(scope: string, customerId: string) {
|
|
30
|
+
const token: Token = {
|
|
31
|
+
access_token: randomBytes(16).toString('base64'),
|
|
32
|
+
token_type: 'Bearer',
|
|
33
|
+
expires_in: 172800,
|
|
34
|
+
scope: scope
|
|
35
|
+
? `${scope} custome_id:${customerId}`
|
|
36
|
+
: `customer_id: ${customerId}`,
|
|
37
|
+
}
|
|
38
|
+
this.tokens.push(token)
|
|
39
|
+
return token
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
validateToken(token: string) {
|
|
30
43
|
if (!this.validate) return true
|
|
31
44
|
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
CustomerDraft,
|
|
5
5
|
CustomerSetAuthenticationModeAction,
|
|
6
6
|
CustomerSetCustomFieldAction,
|
|
7
|
+
DuplicateFieldError,
|
|
7
8
|
InvalidInputError,
|
|
8
9
|
InvalidJsonInputError,
|
|
9
10
|
} from '@commercetools/platform-sdk'
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
AbstractResourceRepository,
|
|
15
16
|
type RepositoryContext,
|
|
16
17
|
} from './abstract.js'
|
|
18
|
+
import { hashPassword } from '../lib/password.js'
|
|
17
19
|
|
|
18
20
|
export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
19
21
|
getTypeId() {
|
|
@@ -21,13 +23,32 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
create(context: RepositoryContext, draft: CustomerDraft): Customer {
|
|
26
|
+
// Check uniqueness
|
|
27
|
+
const results = this._storage.query(context.projectKey, this.getTypeId(), {
|
|
28
|
+
where: [`email="${draft.email.toLocaleLowerCase()}"`],
|
|
29
|
+
})
|
|
30
|
+
if (results.count > 0) {
|
|
31
|
+
throw new CommercetoolsError<any>({
|
|
32
|
+
code: 'CustomerAlreadyExists',
|
|
33
|
+
statusCode: 400,
|
|
34
|
+
message:
|
|
35
|
+
'There is already an existing customer with the provided email.',
|
|
36
|
+
errors: [
|
|
37
|
+
{
|
|
38
|
+
code: 'DuplicateField',
|
|
39
|
+
message: `Customer with email '${draft.email}' already exists.`,
|
|
40
|
+
duplicateValue: draft.email,
|
|
41
|
+
field: 'email',
|
|
42
|
+
} as DuplicateFieldError,
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
24
47
|
const resource: Customer = {
|
|
25
48
|
...getBaseResourceProperties(),
|
|
26
49
|
authenticationMode: draft.authenticationMode || 'Password',
|
|
27
|
-
email: draft.email,
|
|
28
|
-
password: draft.password
|
|
29
|
-
? Buffer.from(draft.password).toString('base64')
|
|
30
|
-
: undefined,
|
|
50
|
+
email: draft.email.toLowerCase(),
|
|
51
|
+
password: draft.password ? hashPassword(draft.password) : undefined,
|
|
31
52
|
isEmailVerified: draft.isEmailVerified || false,
|
|
32
53
|
addresses: [],
|
|
33
54
|
}
|
|
@@ -36,11 +57,14 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
|
36
57
|
}
|
|
37
58
|
|
|
38
59
|
getMe(context: RepositoryContext): Customer | undefined {
|
|
60
|
+
// grab the first customer you can find for now. In the future we should
|
|
61
|
+
// use the customer id from the scope of the token
|
|
39
62
|
const results = this._storage.query(
|
|
40
63
|
context.projectKey,
|
|
41
64
|
this.getTypeId(),
|
|
42
65
|
{}
|
|
43
|
-
)
|
|
66
|
+
)
|
|
67
|
+
|
|
44
68
|
if (results.count > 0) {
|
|
45
69
|
return results.results[0] as Customer
|
|
46
70
|
}
|
|
@@ -76,9 +100,7 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
|
76
100
|
return
|
|
77
101
|
}
|
|
78
102
|
if (authMode === 'Password') {
|
|
79
|
-
resource.password = password
|
|
80
|
-
? Buffer.from(password).toString('base64')
|
|
81
|
-
: undefined
|
|
103
|
+
resource.password = password ? hashPassword(password) : undefined
|
|
82
104
|
return
|
|
83
105
|
}
|
|
84
106
|
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
@@ -2,6 +2,7 @@ import { Request, Response, Router } from 'express'
|
|
|
2
2
|
import { CustomerRepository } from '../repositories/customer.js'
|
|
3
3
|
import { getRepositoryContext } from '../repositories/helpers.js'
|
|
4
4
|
import AbstractService from './abstract.js'
|
|
5
|
+
import { hashPassword } from '../lib/password.js'
|
|
5
6
|
|
|
6
7
|
export class MyCustomerService extends AbstractService {
|
|
7
8
|
public repository: CustomerRepository
|
|
@@ -51,7 +52,7 @@ export class MyCustomerService extends AbstractService {
|
|
|
51
52
|
|
|
52
53
|
signIn(request: Request, response: Response) {
|
|
53
54
|
const { email, password } = request.body
|
|
54
|
-
const encodedPassword =
|
|
55
|
+
const encodedPassword = hashPassword(password)
|
|
55
56
|
|
|
56
57
|
const result = this.repository.query(getRepositoryContext(request), {
|
|
57
58
|
where: [`email = "${email}"`, `password = "${encodedPassword}"`],
|