session-sync-auth-site 0.5.3 → 0.5.5
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/README.md +6 -0
- package/package.json +1 -1
- package/src/createUser.js +1 -1
- package/src/setUpSessionSyncAuthRoutes.js +124 -66
package/README.md
CHANGED
|
@@ -88,6 +88,12 @@ setUpSessionSyncAuthRoutes({
|
|
|
88
88
|
// typically coincide with `extraUserTableSelectValues` above.
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
|
+
mergeUser: async ({ userId, mergeToUserId }) => { // optional (when absent, merge requests will succeed even though no data is merged for this site)
|
|
92
|
+
// move all of userId's data to mergeToUserId
|
|
93
|
+
},
|
|
94
|
+
deleteUser: async ({ id, email }) => { // optional (when absent, the appropriate rows from users and sessions are deleted)
|
|
95
|
+
// delete all of userId's data, including appropriate rows from users and sessions tables
|
|
96
|
+
},
|
|
91
97
|
protocol: 'https',
|
|
92
98
|
paths: {
|
|
93
99
|
getUser: '/get-user',
|
package/package.json
CHANGED
package/src/createUser.js
CHANGED
|
@@ -11,7 +11,7 @@ const createUser = async ({
|
|
|
11
11
|
siteId,
|
|
12
12
|
authDomain,
|
|
13
13
|
jwtSecret,
|
|
14
|
-
protocol=req.sessionSyncAuthProtocol || `https`,
|
|
14
|
+
protocol=(setup || req).sessionSyncAuthProtocol || `https`,
|
|
15
15
|
} = setup || await req.getSessionSyncAuthSetupInfo()
|
|
16
16
|
|
|
17
17
|
const createUserResult = await fetch(
|
|
@@ -8,6 +8,8 @@ const setUpSessionSyncAuthRoutes = ({
|
|
|
8
8
|
authDomain,
|
|
9
9
|
jwtSecret,
|
|
10
10
|
getSetupInfo, // for multi-tenancy setup; sent req and must return the siteId, authDomain, and jwtSecret
|
|
11
|
+
mergeUser,
|
|
12
|
+
deleteUser,
|
|
11
13
|
protocol='https',
|
|
12
14
|
paths: {
|
|
13
15
|
getUser='/get-user',
|
|
@@ -105,13 +107,11 @@ const setUpSessionSyncAuthRoutes = ({
|
|
|
105
107
|
sessionTableColNameMap,
|
|
106
108
|
} = req.sessionSyncAuthSiteOptions
|
|
107
109
|
|
|
108
|
-
const { users } = jwt.verify(payload, jwtSecret)
|
|
110
|
+
const { users, usersToDelete } = jwt.verify(payload, jwtSecret)
|
|
109
111
|
|
|
110
|
-
if(!users) throw "Invalid payload. Missing `payload.user`."
|
|
111
|
-
if(!(users instanceof Array)) throw "Invalid payload. `payload.users` must be an array."
|
|
112
|
-
|
|
113
|
-
const queries = []
|
|
114
|
-
const variables = {}
|
|
112
|
+
if(!users && !usersToDelete) throw "Invalid payload. Missing `payload.user`."
|
|
113
|
+
if(users && !(users instanceof Array)) throw "Invalid payload. `payload.users` must be an array."
|
|
114
|
+
if(usersToDelete && !(usersToDelete instanceof Array)) throw "Invalid payload. `payload.usersToDelete` must be an array."
|
|
115
115
|
|
|
116
116
|
const getSnakeCaseOfKeys = (obj, allowedKeys) => {
|
|
117
117
|
const newObj = {}
|
|
@@ -143,91 +143,149 @@ const setUpSessionSyncAuthRoutes = ({
|
|
|
143
143
|
})
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
users
|
|
147
|
-
const { id, sessions, createdAt, updatedAt } = user
|
|
146
|
+
if(users) {
|
|
148
147
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if(!(sessions instanceof Array)) throw "Invalid payload. `payload.users[].sessions` must be an array."
|
|
152
|
-
if(!createdAt) throw "Invalid payload. Item in `payload.users` missing `createdAt` key."
|
|
153
|
-
if(!updatedAt) throw "Invalid payload. Item in `payload.users` missing `updatedAt` key."
|
|
148
|
+
const queries = []
|
|
149
|
+
const variables = {}
|
|
154
150
|
|
|
155
|
-
|
|
151
|
+
users.forEach(user => {
|
|
152
|
+
const { id, sessions, createdAt, updatedAt } = user
|
|
156
153
|
|
|
157
|
-
|
|
154
|
+
if(!id) throw "Invalid payload. Item in `payload.users` missing `id` key."
|
|
155
|
+
if(!sessions) throw "Invalid payload. Item in `payload.users` missing `sessions` key."
|
|
156
|
+
if(!(sessions instanceof Array)) throw "Invalid payload. `payload.users[].sessions` must be an array."
|
|
157
|
+
if(!createdAt) throw "Invalid payload. Item in `payload.users` missing `createdAt` key."
|
|
158
|
+
if(!updatedAt) throw "Invalid payload. Item in `payload.users` missing `updatedAt` key."
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
user,
|
|
161
|
-
[ 'id', 'email', 'name', 'image', 'language', 'gender', 'created_at', 'updated_at' ],
|
|
162
|
-
)
|
|
160
|
+
convertMsTimestampsToDateTimeStrings(user)
|
|
163
161
|
|
|
164
|
-
|
|
165
|
-
variables[`user__${id}`].language = variables[`user__${id}`].language.split('-')[0]
|
|
166
|
-
}
|
|
162
|
+
// add/update the user
|
|
167
163
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
164
|
+
variables[`user__${id}`] = getSnakeCaseOfKeys(
|
|
165
|
+
user,
|
|
166
|
+
[ 'id', 'email', 'name', 'image', 'language', 'gender', 'created_at', 'updated_at' ],
|
|
167
|
+
)
|
|
171
168
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
...extraUserTableValues,
|
|
175
|
-
...variables[`user__${id}`],
|
|
169
|
+
if(languageColType !== 'IETF') {
|
|
170
|
+
variables[`user__${id}`].language = variables[`user__${id}`].language.split('-')[0]
|
|
176
171
|
}
|
|
177
|
-
}
|
|
178
172
|
|
|
179
|
-
|
|
173
|
+
if(languageColType === '639-1') {
|
|
174
|
+
variables[`user__${id}`].language = iso6393To1[variables[`user__${id}`].language] || 'en'
|
|
175
|
+
}
|
|
180
176
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
177
|
+
if(extraUserTableValues) {
|
|
178
|
+
variables[`user__${id}`] = {
|
|
179
|
+
...extraUserTableValues,
|
|
180
|
+
...variables[`user__${id}`],
|
|
181
|
+
}
|
|
182
|
+
}
|
|
185
183
|
|
|
186
|
-
|
|
184
|
+
mapKeys(variables[`user__${id}`], 'user')
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
queries.push(`
|
|
187
|
+
INSERT INTO \`${userTableName}\` SET :user__${id}
|
|
188
|
+
ON DUPLICATE KEY UPDATE :user__${id}
|
|
189
|
+
`)
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
if(!createdAt) throw "Invalid payload. Item in `payload.users[].sessions` missing `createdAt` key."
|
|
191
|
+
// add the sessions
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
sessions.forEach(session => {
|
|
194
|
+
const { accessToken, createdAt } = session
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
if(!accessToken) throw "Invalid payload. Item in `payload.users[].sessions` missing `accessToken` key."
|
|
197
|
+
if(!createdAt) throw "Invalid payload. Item in `payload.users[].sessions` missing `createdAt` key."
|
|
198
|
+
|
|
199
|
+
convertMsTimestampsToDateTimeStrings(session)
|
|
200
|
+
|
|
201
|
+
variables[`session__${accessToken}`] = {
|
|
202
|
+
...getSnakeCaseOfKeys(
|
|
203
|
+
session,
|
|
204
|
+
[ 'created_at', 'access_token' ],
|
|
205
|
+
),
|
|
206
|
+
user_id: id,
|
|
207
|
+
}
|
|
208
|
+
mapKeys(variables[`session__${accessToken}`], 'session')
|
|
209
|
+
|
|
210
|
+
queries.push(`
|
|
211
|
+
INSERT IGNORE INTO \`${sessionTableName}\` SET :session__${accessToken}
|
|
212
|
+
`)
|
|
213
|
+
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
// delete old sessions
|
|
217
|
+
|
|
218
|
+
variables[`userId__${id}`] = id
|
|
219
|
+
variables[`accessTokens__${id}`] = [
|
|
220
|
+
'dummy_token', // so the SQL is still valid even if there are no sessions
|
|
221
|
+
...sessions.map(({ accessToken }) => accessToken),
|
|
222
|
+
]
|
|
204
223
|
|
|
205
224
|
queries.push(`
|
|
206
|
-
|
|
225
|
+
DELETE FROM \`${sessionTableName}\`
|
|
226
|
+
WHERE \`${(sessionTableColNameMap.user_id || `user_id`).replace(/`/g, '')}\` = :userId__${id}
|
|
227
|
+
AND \`${(sessionTableColNameMap.access_token || `access_token`).replace(/`/g, '')}\` NOT IN (:accessTokens__${id})
|
|
207
228
|
`)
|
|
208
229
|
|
|
209
230
|
})
|
|
210
231
|
|
|
211
|
-
|
|
232
|
+
await global.sessionSyncAuthSiteConnection.asyncQuery(
|
|
233
|
+
queries.join(';'),
|
|
234
|
+
variables,
|
|
235
|
+
)
|
|
212
236
|
|
|
213
|
-
|
|
214
|
-
variables[`accessTokens__${id}`] = [
|
|
215
|
-
'dummy_token', // so the SQL is still valid even if there are no sessions
|
|
216
|
-
...sessions.map(({ accessToken }) => accessToken),
|
|
217
|
-
]
|
|
237
|
+
}
|
|
218
238
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
239
|
+
if(usersToDelete) {
|
|
240
|
+
|
|
241
|
+
await Promise.all(usersToDelete.map(async user => {
|
|
242
|
+
const { id, email, mergeToUserId } = user
|
|
243
|
+
|
|
244
|
+
if(!id) throw "Invalid payload. Item in `payload.usersToDelete` missing `id` key."
|
|
245
|
+
if(!email) throw "Invalid payload. Item in `payload.usersToDelete` missing `email` key."
|
|
246
|
+
|
|
247
|
+
const [ user ] = await global.sessionSyncAuthSiteConnection.asyncQuery(
|
|
248
|
+
`
|
|
249
|
+
SELECT email
|
|
250
|
+
FROM \`${userTableName}\`
|
|
251
|
+
WHERE \`${(userTableColNameMap.id || `id`).replace(/`/g, '')}\` = :userId
|
|
252
|
+
`,
|
|
253
|
+
{
|
|
254
|
+
userId: id,
|
|
255
|
+
},
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if(!user) return // gracefully handle non-existent user
|
|
259
|
+
if(user.email !== email) throw "The `id` and `email` passed in do not coorespond."
|
|
260
|
+
|
|
261
|
+
if(mergeToUserId && mergeUser) {
|
|
262
|
+
await mergeUser({
|
|
263
|
+
id,
|
|
264
|
+
mergeToUserId,
|
|
265
|
+
})
|
|
266
|
+
}
|
|
224
267
|
|
|
225
|
-
|
|
268
|
+
if(deleteUser) {
|
|
269
|
+
await deleteUser({ id })
|
|
270
|
+
} else {
|
|
271
|
+
await global.sessionSyncAuthSiteConnection.asyncQuery(
|
|
272
|
+
`
|
|
273
|
+
DELETE FROM \`${sessionTableName}\`
|
|
274
|
+
WHERE \`${(sessionTableColNameMap.user_id || `user_id`).replace(/`/g, '')}\` = :userId
|
|
275
|
+
;
|
|
276
|
+
|
|
277
|
+
DELETE FROM \`${userTableName}\`
|
|
278
|
+
WHERE \`${(userTableColNameMap.id || `id`).replace(/`/g, '')}\` = :userId
|
|
279
|
+
`,
|
|
280
|
+
{
|
|
281
|
+
userId: id,
|
|
282
|
+
},
|
|
283
|
+
)
|
|
284
|
+
}
|
|
226
285
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
)
|
|
286
|
+
}))
|
|
287
|
+
|
|
288
|
+
}
|
|
231
289
|
|
|
232
290
|
res.json({ success: true })
|
|
233
291
|
|