@live-change/google-authentication-service 0.8.13 → 0.8.15
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/index.js +341 -172
- package/package.json +4 -4
package/index.js
CHANGED
|
@@ -1,51 +1,236 @@
|
|
|
1
1
|
import App from '@live-change/framework'
|
|
2
2
|
const app = App.app()
|
|
3
3
|
|
|
4
|
+
import Debug from 'debug'
|
|
5
|
+
const debug = Debug('services:googleAuthentication')
|
|
6
|
+
|
|
4
7
|
import { OAuth2Client } from 'google-auth-library'
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
const googClient = new OAuth2Client(googClientId)
|
|
9
|
+
import user from '@live-change/user-service'
|
|
8
10
|
|
|
9
11
|
const definition = app.createServiceDefinition({
|
|
10
12
|
name: "googleAuthentication",
|
|
11
|
-
|
|
13
|
+
use: [ user ]
|
|
12
14
|
})
|
|
15
|
+
const config = definition.config
|
|
16
|
+
|
|
17
|
+
const googleClientId = config.clientId || process.env.GOOGLE_CLIENT_ID
|
|
18
|
+
const googleClient = new OAuth2Client(googleClientId)
|
|
13
19
|
|
|
20
|
+
const User = definition.foreignModel("user", "User")
|
|
14
21
|
|
|
15
|
-
const
|
|
22
|
+
const googleProperties = {
|
|
23
|
+
email: {
|
|
24
|
+
type: String
|
|
25
|
+
},
|
|
26
|
+
email_verified: {
|
|
27
|
+
type: Boolean
|
|
28
|
+
},
|
|
29
|
+
name: {
|
|
30
|
+
type: String
|
|
31
|
+
},
|
|
32
|
+
given_name: {
|
|
33
|
+
type: String
|
|
34
|
+
},
|
|
35
|
+
family_name: {
|
|
36
|
+
type: String
|
|
37
|
+
},
|
|
38
|
+
picture: {
|
|
39
|
+
type: String
|
|
40
|
+
},
|
|
41
|
+
locale: {
|
|
42
|
+
type: String
|
|
43
|
+
}
|
|
44
|
+
}
|
|
16
45
|
|
|
17
|
-
const
|
|
18
|
-
name: "
|
|
46
|
+
const Account = definition.model({
|
|
47
|
+
name: "Account",
|
|
19
48
|
properties: {
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
...googleProperties
|
|
50
|
+
},
|
|
51
|
+
userItem: {
|
|
52
|
+
userReadAccess: () => true
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
definition.event({
|
|
57
|
+
name: 'accountConnected',
|
|
58
|
+
properties: {
|
|
59
|
+
account: {
|
|
60
|
+
type: String,
|
|
61
|
+
validation: ['nonEmpty']
|
|
22
62
|
},
|
|
23
|
-
|
|
24
|
-
type:
|
|
63
|
+
user: {
|
|
64
|
+
type: User,
|
|
65
|
+
validation: ['nonEmpty']
|
|
25
66
|
},
|
|
26
|
-
|
|
27
|
-
type:
|
|
67
|
+
data: {
|
|
68
|
+
type: Object,
|
|
69
|
+
properties: googleProperties,
|
|
70
|
+
validation: ['nonEmpty']
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
async execute({ user, account, data }) {
|
|
74
|
+
await Account.create({
|
|
75
|
+
...data,
|
|
76
|
+
id: account,
|
|
77
|
+
user
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
definition.event({
|
|
83
|
+
name: "accountDisconnected",
|
|
84
|
+
properties: {
|
|
85
|
+
account: {
|
|
86
|
+
type: String,
|
|
87
|
+
validation: ['nonEmpty']
|
|
28
88
|
},
|
|
29
89
|
user: {
|
|
30
|
-
type: User
|
|
90
|
+
type: User,
|
|
91
|
+
validation: ['nonEmpty']
|
|
31
92
|
}
|
|
32
93
|
},
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
94
|
+
async execute({ account }) {
|
|
95
|
+
await Account.delete(account)
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
definition.trigger({
|
|
100
|
+
name: "signInGoogle",
|
|
101
|
+
properties: {
|
|
102
|
+
account: {
|
|
103
|
+
type: String,
|
|
104
|
+
validation: ['nonEmpty']
|
|
36
105
|
}
|
|
37
106
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
107
|
+
async execute({ account, session }, { service }, _emit) {
|
|
108
|
+
const accountData = await Account.get(account)
|
|
109
|
+
if(!accountData) throw { properties: { email: 'notFound' } }
|
|
110
|
+
const { user } = accountData
|
|
111
|
+
return service.trigger({
|
|
112
|
+
type: 'signIn',
|
|
113
|
+
user, session
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
async function downloadData(user, data, service) {
|
|
119
|
+
await service.trigger({
|
|
120
|
+
type: 'setIdentification',
|
|
121
|
+
sessionOrUserType: 'user',
|
|
122
|
+
sessionOrUser: user,
|
|
123
|
+
overwrite: false,
|
|
124
|
+
name: data.name,
|
|
125
|
+
givenName: data.given_name,
|
|
126
|
+
firstName: data.given_name,
|
|
127
|
+
familyName: data.family_name,
|
|
128
|
+
lastName: data.family_name,
|
|
129
|
+
})
|
|
130
|
+
if(data.picture) {
|
|
131
|
+
const downloadAndUpdateImage = (async () => {
|
|
132
|
+
const picture = await service.trigger('pictures', {
|
|
133
|
+
type: "createPictureFromUrl",
|
|
134
|
+
ownerType: 'user_User',
|
|
135
|
+
owner: user,
|
|
136
|
+
name: "google-profile-picture",
|
|
137
|
+
purpose: "users-updatePicture-picture",
|
|
138
|
+
url: data.picture,
|
|
139
|
+
cropped: true
|
|
140
|
+
})
|
|
141
|
+
await service.trigger({
|
|
142
|
+
type: 'setIdentification',
|
|
143
|
+
sessionOrUserType: 'user',
|
|
144
|
+
sessionOrUser: user,
|
|
145
|
+
overwrite: false,
|
|
146
|
+
picture
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
downloadAndUpdateImage()
|
|
150
|
+
}
|
|
151
|
+
if(data.email_verified) {
|
|
152
|
+
await service.trigger({
|
|
153
|
+
type: 'connectEmail',
|
|
154
|
+
email: data.email,
|
|
155
|
+
user
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
definition.trigger({
|
|
161
|
+
name: "connectGoogle",
|
|
162
|
+
properties: {
|
|
163
|
+
user: {
|
|
164
|
+
type: User,
|
|
165
|
+
validation: ['nonEmpty']
|
|
166
|
+
},
|
|
167
|
+
account: {
|
|
168
|
+
type: String,
|
|
169
|
+
validation: ['nonEmpty']
|
|
170
|
+
},
|
|
171
|
+
data: {
|
|
172
|
+
type: Object,
|
|
173
|
+
properties: googleProperties,
|
|
174
|
+
validation: ['nonEmpty']
|
|
175
|
+
},
|
|
176
|
+
transferOwnership: {
|
|
177
|
+
type: Boolean,
|
|
178
|
+
default: false
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
async execute({ user, account, data, transferOwnership }, { service }, emit) {
|
|
182
|
+
const accountData = await Account.get(account)
|
|
183
|
+
if(accountData) {
|
|
184
|
+
if(accountData.user !== user) {
|
|
185
|
+
if(transferOwnership) {
|
|
186
|
+
emit({
|
|
187
|
+
'type': 'userOwnedAccountTransferred',
|
|
188
|
+
account, to: user
|
|
189
|
+
})
|
|
190
|
+
await downloadData(user, data, service)
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
throw 'alreadyConnectedElsewhere'
|
|
42
194
|
}
|
|
195
|
+
throw 'alreadyConnected'
|
|
43
196
|
}
|
|
197
|
+
emit({
|
|
198
|
+
type: 'accountConnected',
|
|
199
|
+
account, user, data
|
|
200
|
+
})
|
|
201
|
+
await service.trigger({
|
|
202
|
+
type: 'googleConnected',
|
|
203
|
+
user, account, data
|
|
204
|
+
})
|
|
205
|
+
await downloadData(user, data, service)
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
definition.trigger({
|
|
210
|
+
name: "disconnectGoogle",
|
|
211
|
+
properties: {
|
|
212
|
+
account: {
|
|
213
|
+
type: String,
|
|
214
|
+
validation: ['nonEmpty']
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
async execute({ account }, { client, service }, emit) {
|
|
218
|
+
const accountData = await Account.get(account)
|
|
219
|
+
if(!accountData) throw 'notFound'
|
|
220
|
+
const { user } = accountData
|
|
221
|
+
emit({
|
|
222
|
+
type: 'accountDisconnected',
|
|
223
|
+
account, user
|
|
224
|
+
})
|
|
225
|
+
await service.trigger({
|
|
226
|
+
type: 'googleDisconnected',
|
|
227
|
+
user, account
|
|
228
|
+
})
|
|
44
229
|
}
|
|
45
230
|
})
|
|
46
231
|
|
|
47
232
|
definition.action({
|
|
48
|
-
name: "
|
|
233
|
+
name: "signIn",
|
|
49
234
|
properties: {
|
|
50
235
|
accessToken: {
|
|
51
236
|
type: String
|
|
@@ -55,188 +240,172 @@ definition.action({
|
|
|
55
240
|
type: User,
|
|
56
241
|
idOnly: true
|
|
57
242
|
},
|
|
58
|
-
|
|
59
|
-
|
|
243
|
+
waitForEvents: true,
|
|
244
|
+
async execute({ accessToken }, { client, service }, emit) {
|
|
245
|
+
const ticket = await googleClient.verifyIdToken({
|
|
60
246
|
idToken: accessToken,
|
|
61
|
-
audience:
|
|
247
|
+
audience: googleClientId
|
|
62
248
|
})
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
emit("session", [{
|
|
71
|
-
type: "loggedIn",
|
|
72
|
-
user: existingLogin.user,
|
|
73
|
-
session: client.sessionId,
|
|
74
|
-
expire: null,
|
|
75
|
-
roles: userRow.roles || []
|
|
76
|
-
}])
|
|
249
|
+
const googleUser = ticket.getPayload()
|
|
250
|
+
debug("GOOGLE USER", googleUser)
|
|
251
|
+
const account = googleUser.sub
|
|
252
|
+
const existingLogin = await Account.get(account)
|
|
253
|
+
const { session } = client
|
|
254
|
+
if(existingLogin) { /// Sign In
|
|
255
|
+
const { user } = existingLogin
|
|
77
256
|
await service.trigger({
|
|
78
|
-
type:
|
|
79
|
-
user,
|
|
80
|
-
session: client.sessionId
|
|
81
|
-
})
|
|
82
|
-
return existingLogin.user
|
|
83
|
-
} else { // Register
|
|
84
|
-
const user = app.generateUid()
|
|
85
|
-
console.log("PIC", googUser.picture)
|
|
86
|
-
let userData = JSON.parse(JSON.stringify({
|
|
87
|
-
name: googUser.name,
|
|
88
|
-
email: googUser.email,
|
|
89
|
-
firstName: googUser.given_name,
|
|
90
|
-
lastName: googUser.family_name
|
|
91
|
-
}))
|
|
92
|
-
|
|
93
|
-
userData = { ...userDataParams, ...userData }
|
|
94
|
-
|
|
95
|
-
await service.trigger({
|
|
96
|
-
type:"OnRegisterStart",
|
|
97
|
-
session: client.sessionId,
|
|
98
|
-
user: user
|
|
257
|
+
type: 'signIn',
|
|
258
|
+
user, session
|
|
99
259
|
})
|
|
260
|
+
return {
|
|
261
|
+
action: 'signIn',
|
|
262
|
+
user
|
|
263
|
+
}
|
|
264
|
+
} else { // Sign up
|
|
265
|
+
throw 'notFound'
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
})
|
|
100
269
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
270
|
+
definition.action({
|
|
271
|
+
name: "signUp",
|
|
272
|
+
properties: {
|
|
273
|
+
accessToken: {
|
|
274
|
+
type: String
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
returns: {
|
|
278
|
+
type: User,
|
|
279
|
+
idOnly: true
|
|
280
|
+
},
|
|
281
|
+
waitForEvents: true,
|
|
282
|
+
async execute({ accessToken }, { client, service }, emit) {
|
|
283
|
+
const ticket = await googleClient.verifyIdToken({
|
|
284
|
+
idToken: accessToken,
|
|
285
|
+
audience: googleClientId
|
|
286
|
+
})
|
|
287
|
+
const googleUser = ticket.getPayload()
|
|
288
|
+
debug("GOOGLE USER", googleUser)
|
|
289
|
+
const account = googleUser.sub
|
|
290
|
+
const existingLogin = await Account.get(account)
|
|
291
|
+
const { session } = client
|
|
292
|
+
if(existingLogin) { /// Sign In
|
|
293
|
+
throw 'alreadyConnected'
|
|
294
|
+
} else { // Sign up
|
|
295
|
+
const user = app.generateUid()
|
|
127
296
|
await service.trigger({
|
|
128
|
-
type:
|
|
129
|
-
|
|
130
|
-
user: user,
|
|
131
|
-
userData
|
|
297
|
+
type: 'connectGoogle',
|
|
298
|
+
user, account, data: googleUser
|
|
132
299
|
})
|
|
133
|
-
emit("session", [{
|
|
134
|
-
type: "loggedIn",
|
|
135
|
-
user,
|
|
136
|
-
session: client.sessionId,
|
|
137
|
-
expire: null,
|
|
138
|
-
roles: []
|
|
139
|
-
}])
|
|
140
300
|
await service.trigger({
|
|
141
|
-
type:
|
|
142
|
-
user,
|
|
143
|
-
session: client.sessionId
|
|
301
|
+
type: 'signUpAndSignIn',
|
|
302
|
+
user, session
|
|
144
303
|
})
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
owner: user,
|
|
150
|
-
name: "google-profile-picture",
|
|
151
|
-
purpose: "users-updatePicture-picture",
|
|
152
|
-
url: googUser.picture,
|
|
153
|
-
cropped: true
|
|
154
|
-
}).then(picture => {
|
|
155
|
-
emit('users', [{
|
|
156
|
-
type: "UserUpdated",
|
|
157
|
-
user,
|
|
158
|
-
data: {
|
|
159
|
-
userData: {
|
|
160
|
-
picture
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}])
|
|
164
|
-
}).catch(e => {})
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return user
|
|
304
|
+
return {
|
|
305
|
+
action: 'signUp',
|
|
306
|
+
user
|
|
307
|
+
}
|
|
168
308
|
}
|
|
169
309
|
}
|
|
170
|
-
|
|
171
310
|
})
|
|
172
311
|
|
|
173
|
-
|
|
174
|
-
name: "
|
|
175
|
-
properties: {
|
|
312
|
+
definition.action({
|
|
313
|
+
name: "signInOrSignUp",
|
|
314
|
+
properties: {
|
|
315
|
+
accessToken: {
|
|
316
|
+
type: String
|
|
317
|
+
}
|
|
318
|
+
},
|
|
176
319
|
returns: {
|
|
177
320
|
type: User,
|
|
178
321
|
idOnly: true
|
|
179
322
|
},
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
323
|
+
waitForEvents: true,
|
|
324
|
+
async execute({ accessToken }, { client, service }, emit) {
|
|
325
|
+
const ticket = await googleClient.verifyIdToken({
|
|
326
|
+
idToken: accessToken,
|
|
327
|
+
audience: googleClientId
|
|
328
|
+
})
|
|
329
|
+
const googleUser = ticket.getPayload()
|
|
330
|
+
debug("GOOGLE USER", googleUser)
|
|
331
|
+
const account = googleUser.sub
|
|
332
|
+
const existingLogin = await Account.get(account)
|
|
333
|
+
const { session } = client
|
|
334
|
+
if(existingLogin) { /// Sign In
|
|
335
|
+
const { user } = existingLogin
|
|
336
|
+
await service.trigger({
|
|
337
|
+
type: 'signIn',
|
|
338
|
+
user, session
|
|
195
339
|
})
|
|
340
|
+
return {
|
|
341
|
+
action: 'signIn',
|
|
342
|
+
user: existingLogin.user
|
|
343
|
+
}
|
|
344
|
+
} else { // Sign up
|
|
345
|
+
const user = app.generateUid()
|
|
346
|
+
await service.trigger({
|
|
347
|
+
type: 'connectGoogle',
|
|
348
|
+
user, account, data: googleUser
|
|
349
|
+
})
|
|
350
|
+
await service.trigger({
|
|
351
|
+
type: 'signUpAndSignIn',
|
|
352
|
+
user, session
|
|
353
|
+
})
|
|
354
|
+
return {
|
|
355
|
+
action: 'signUp',
|
|
356
|
+
user
|
|
357
|
+
}
|
|
196
358
|
}
|
|
197
|
-
emit("facebookLogin", events)
|
|
198
359
|
}
|
|
199
|
-
})
|
|
360
|
+
})
|
|
200
361
|
|
|
201
|
-
definition.
|
|
202
|
-
name: "
|
|
362
|
+
definition.action({
|
|
363
|
+
name: "connectGoogle",
|
|
203
364
|
properties: {
|
|
204
|
-
|
|
205
|
-
type:
|
|
365
|
+
accessToken: {
|
|
366
|
+
type: String
|
|
367
|
+
},
|
|
368
|
+
transferOwnership: {
|
|
369
|
+
type: Boolean,
|
|
370
|
+
default: false
|
|
206
371
|
}
|
|
207
372
|
},
|
|
208
|
-
async execute({
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
373
|
+
async execute({ accessToken, transferOwnership }, { client, service }, emit) {
|
|
374
|
+
const ticket = await googleClient.verifyIdToken({
|
|
375
|
+
idToken: accessToken,
|
|
376
|
+
audience: googleClientId
|
|
377
|
+
})
|
|
378
|
+
const user = client.user
|
|
379
|
+
if(!user) throw 'notAuthorized'
|
|
380
|
+
const googleUser = ticket.getPayload()
|
|
381
|
+
debug("GOOGLE USER", googleUser)
|
|
382
|
+
const account = googleUser.sub
|
|
383
|
+
await service.trigger({
|
|
384
|
+
type: 'connectGoogle',
|
|
385
|
+
user, account, data: googleUser,
|
|
386
|
+
transferOwnership
|
|
387
|
+
})
|
|
222
388
|
}
|
|
223
389
|
})
|
|
224
390
|
|
|
225
|
-
definition.
|
|
226
|
-
|
|
391
|
+
definition.action({
|
|
392
|
+
name: "disconnectGoogle",
|
|
227
393
|
properties: {
|
|
228
|
-
|
|
229
|
-
type:
|
|
230
|
-
|
|
394
|
+
account: {
|
|
395
|
+
type: String,
|
|
396
|
+
validation: ['nonEmpty']
|
|
231
397
|
}
|
|
232
398
|
},
|
|
233
|
-
async execute({
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
399
|
+
async execute({ account }, { client, service }, emit) {
|
|
400
|
+
const accountData = await Account.get(account)
|
|
401
|
+
if(!accountData) throw 'notFound'
|
|
402
|
+
const { user } = accountData
|
|
403
|
+
if(user !== client.user) throw 'notAuthorized'
|
|
404
|
+
await service.trigger({
|
|
405
|
+
type: 'disconnectGoogle',
|
|
406
|
+
user, account
|
|
407
|
+
})
|
|
238
408
|
}
|
|
239
409
|
})
|
|
240
410
|
|
|
241
|
-
|
|
242
411
|
export default definition
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/google-authentication-service",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.15",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"url": "https://www.viamage.com/"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@live-change/framework": "^0.8.
|
|
25
|
-
"@live-change/relations-plugin": "^0.8.
|
|
24
|
+
"@live-change/framework": "^0.8.15",
|
|
25
|
+
"@live-change/relations-plugin": "^0.8.15",
|
|
26
26
|
"google-auth-library": "9.0.0"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "4897eefbf3ce9ace57630127da89503c71114563",
|
|
29
29
|
"type": "module"
|
|
30
30
|
}
|