@live-change/user-frontend 0.8.33 → 0.8.35
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/.nx/cache/file-map.json +37 -49
- package/.nx/cache/nx_files.nxt +0 -0
- package/front/src/google-access/AccessGained.vue +71 -0
- package/front/src/google-access/GetAccess.vue +72 -0
- package/front/src/google-access/routes.js +15 -0
- package/front/src/router.js +3 -1
- package/front/src/sign/GoogleAuth.vue +30 -56
- package/front/src/sign/GoogleAuthReturn.vue +14 -15
- package/front/src/sign/routes.js +2 -0
- package/front/src/utils/googleAuth.js +29 -0
- package/package.json +28 -28
- package/server/app.config.js +5 -2
- package/server/services.list.js +4 -2
- package/front/src/utils/googleApi.js +0 -50
package/.nx/cache/file-map.json
CHANGED
|
@@ -2,30 +2,30 @@
|
|
|
2
2
|
"version": "6.0",
|
|
3
3
|
"nxVersion": "18.0.6",
|
|
4
4
|
"deps": {
|
|
5
|
-
"@live-change/cli": "0.8.
|
|
6
|
-
"@live-change/dao": "0.8.
|
|
7
|
-
"@live-change/dao-vue3": "0.8.
|
|
8
|
-
"@live-change/dao-websocket": "0.8.
|
|
9
|
-
"@live-change/email-service": "0.8.
|
|
10
|
-
"@live-change/framework": "0.8.
|
|
11
|
-
"@live-change/identicon-service": "0.8.
|
|
12
|
-
"@live-change/image-frontend": "0.8.
|
|
13
|
-
"@live-change/message-authentication-service": "0.8.
|
|
14
|
-
"@live-change/notification-service": "0.8.
|
|
15
|
-
"@live-change/password-authentication-service": "0.8.
|
|
16
|
-
"@live-change/pattern": "0.8.
|
|
17
|
-
"@live-change/secret-code-service": "0.8.
|
|
18
|
-
"@live-change/secret-link-service": "0.8.
|
|
19
|
-
"@live-change/security-frontend": "0.8.
|
|
20
|
-
"@live-change/security-service": "0.8.
|
|
21
|
-
"@live-change/session-service": "0.8.
|
|
22
|
-
"@live-change/timer-service": "0.8.
|
|
23
|
-
"@live-change/upload-service": "0.8.
|
|
24
|
-
"@live-change/user-identification-service": "0.8.
|
|
25
|
-
"@live-change/user-service": "0.8.
|
|
26
|
-
"@live-change/vue3-components": "0.8.
|
|
27
|
-
"@live-change/vue3-ssr": "0.8.
|
|
28
|
-
"@vueuse/core": "^10.
|
|
5
|
+
"@live-change/cli": "0.8.33",
|
|
6
|
+
"@live-change/dao": "0.8.33",
|
|
7
|
+
"@live-change/dao-vue3": "0.8.33",
|
|
8
|
+
"@live-change/dao-websocket": "0.8.33",
|
|
9
|
+
"@live-change/email-service": "0.8.33",
|
|
10
|
+
"@live-change/framework": "0.8.33",
|
|
11
|
+
"@live-change/identicon-service": "0.8.33",
|
|
12
|
+
"@live-change/image-frontend": "0.8.33",
|
|
13
|
+
"@live-change/message-authentication-service": "0.8.33",
|
|
14
|
+
"@live-change/notification-service": "0.8.33",
|
|
15
|
+
"@live-change/password-authentication-service": "0.8.33",
|
|
16
|
+
"@live-change/pattern": "0.8.33",
|
|
17
|
+
"@live-change/secret-code-service": "0.8.33",
|
|
18
|
+
"@live-change/secret-link-service": "0.8.33",
|
|
19
|
+
"@live-change/security-frontend": "0.8.33",
|
|
20
|
+
"@live-change/security-service": "0.8.33",
|
|
21
|
+
"@live-change/session-service": "0.8.33",
|
|
22
|
+
"@live-change/timer-service": "0.8.33",
|
|
23
|
+
"@live-change/upload-service": "0.8.33",
|
|
24
|
+
"@live-change/user-identification-service": "0.8.33",
|
|
25
|
+
"@live-change/user-service": "0.8.33",
|
|
26
|
+
"@live-change/vue3-components": "0.8.33",
|
|
27
|
+
"@live-change/vue3-ssr": "0.8.33",
|
|
28
|
+
"@vueuse/core": "^10.11.0",
|
|
29
29
|
"codeceptjs-assert": "^0.0.5",
|
|
30
30
|
"codeceptjs-video-helper": "0.1.3",
|
|
31
31
|
"compression": "^1.7.4",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"unique-names-generator": "4.7.1",
|
|
41
41
|
"v-shared-element": "3.1.1",
|
|
42
42
|
"vue-meta": "^3.0.0-alpha.9",
|
|
43
|
-
"vue-router": "^4.
|
|
43
|
+
"vue-router": "^4.3.3",
|
|
44
44
|
"vue3-scroll-border": "0.1.6",
|
|
45
45
|
"wtfnode": "^0.9.1",
|
|
46
|
-
"@live-change/codeceptjs-helper": "0.8.
|
|
46
|
+
"@live-change/codeceptjs-helper": "0.8.33",
|
|
47
47
|
"codeceptjs": "^3.5.12",
|
|
48
48
|
"generate-password": "1.7.1",
|
|
49
49
|
"playwright": "^1.41.2",
|
|
@@ -58,15 +58,7 @@
|
|
|
58
58
|
"nonProjectFiles": [
|
|
59
59
|
{
|
|
60
60
|
"file": ".gitignore",
|
|
61
|
-
"hash": "
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"file": "build-stats/ssr-srcentryserverjs-outDir-distserver.html",
|
|
65
|
-
"hash": "17084642017258807740"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"file": "build-stats/ssrManifest-outDir-distclient.html",
|
|
69
|
-
"hash": "3717210539203410457"
|
|
61
|
+
"hash": "16223102139109646162"
|
|
70
62
|
},
|
|
71
63
|
{
|
|
72
64
|
"file": "e2e/codecept.conf.js",
|
|
@@ -132,10 +124,6 @@
|
|
|
132
124
|
"file": "e2e/steps_file.js",
|
|
133
125
|
"hash": "2840236016458073038"
|
|
134
126
|
},
|
|
135
|
-
{
|
|
136
|
-
"file": "front/components.d.ts",
|
|
137
|
-
"hash": "16126346593933999340"
|
|
138
|
-
},
|
|
139
127
|
{
|
|
140
128
|
"file": "front/index.html",
|
|
141
129
|
"hash": "14592446545376477605"
|
|
@@ -162,7 +150,7 @@
|
|
|
162
150
|
},
|
|
163
151
|
{
|
|
164
152
|
"file": "front/src/App.vue",
|
|
165
|
-
"hash": "
|
|
153
|
+
"hash": "2987862695029806083"
|
|
166
154
|
},
|
|
167
155
|
{
|
|
168
156
|
"file": "front/src/Index.vue",
|
|
@@ -238,7 +226,7 @@
|
|
|
238
226
|
},
|
|
239
227
|
{
|
|
240
228
|
"file": "front/src/locale/LocaleSettings.vue",
|
|
241
|
-
"hash": "
|
|
229
|
+
"hash": "15462056023784231614"
|
|
242
230
|
},
|
|
243
231
|
{
|
|
244
232
|
"file": "front/src/locale/routes.js",
|
|
@@ -386,11 +374,11 @@
|
|
|
386
374
|
},
|
|
387
375
|
{
|
|
388
376
|
"file": "front/src/sign/GoogleAuth.vue",
|
|
389
|
-
"hash": "
|
|
377
|
+
"hash": "5043472338996276712"
|
|
390
378
|
},
|
|
391
379
|
{
|
|
392
380
|
"file": "front/src/sign/GoogleAuthReturn.vue",
|
|
393
|
-
"hash": "
|
|
381
|
+
"hash": "11578892278379018497"
|
|
394
382
|
},
|
|
395
383
|
{
|
|
396
384
|
"file": "front/src/sign/SignInEmail.vue",
|
|
@@ -418,15 +406,15 @@
|
|
|
418
406
|
},
|
|
419
407
|
{
|
|
420
408
|
"file": "front/src/sign/routes.js",
|
|
421
|
-
"hash": "
|
|
409
|
+
"hash": "731553876160166852"
|
|
422
410
|
},
|
|
423
411
|
{
|
|
424
412
|
"file": "front/src/utils/countries.js",
|
|
425
413
|
"hash": "6201169448865628496"
|
|
426
414
|
},
|
|
427
415
|
{
|
|
428
|
-
"file": "front/src/utils/
|
|
429
|
-
"hash": "
|
|
416
|
+
"file": "front/src/utils/googleAuth.js",
|
|
417
|
+
"hash": "10682927559112869908"
|
|
430
418
|
},
|
|
431
419
|
{
|
|
432
420
|
"file": "front/vite.config.js",
|
|
@@ -438,11 +426,11 @@
|
|
|
438
426
|
},
|
|
439
427
|
{
|
|
440
428
|
"file": "package.json",
|
|
441
|
-
"hash": "
|
|
429
|
+
"hash": "12911801514831005291"
|
|
442
430
|
},
|
|
443
431
|
{
|
|
444
432
|
"file": "server/app.config.js",
|
|
445
|
-
"hash": "
|
|
433
|
+
"hash": "18401554844996247569"
|
|
446
434
|
},
|
|
447
435
|
{
|
|
448
436
|
"file": "server/init-functions.js",
|
|
@@ -462,7 +450,7 @@
|
|
|
462
450
|
},
|
|
463
451
|
{
|
|
464
452
|
"file": "server/start.js",
|
|
465
|
-
"hash": "
|
|
453
|
+
"hash": "12152681523604331573"
|
|
466
454
|
}
|
|
467
455
|
]
|
|
468
456
|
}
|
package/.nx/cache/nx_files.nxt
CHANGED
|
Binary file
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
|
|
3
|
+
<div class="surface-card border-round shadow-2 p-4">
|
|
4
|
+
<div class="text-900 font-medium mb-3 text-xl mb-4">Signed In</div>
|
|
5
|
+
<p class="mt-0 p-0 line-height-3">
|
|
6
|
+
Congratulations! You added offline access to your account. Now your account have access to:
|
|
7
|
+
<ul>
|
|
8
|
+
<li v-for="access in accessList">
|
|
9
|
+
{{ access }}
|
|
10
|
+
</li>
|
|
11
|
+
</ul>
|
|
12
|
+
<!-- <pre>{{ offlineAccess }}</pre>-->
|
|
13
|
+
</p>
|
|
14
|
+
<div v-if="afterGoogleAccessGained" class="flex flex-row align-items-center">
|
|
15
|
+
<router-link :to="afterGoogleAccessGained" class="no-underline">
|
|
16
|
+
<Button label="Next" v-ripple />
|
|
17
|
+
</router-link>
|
|
18
|
+
<p class="ml-4" v-if="isMounted && redirectTime">
|
|
19
|
+
Redirect in {{ pluralize('second', Math.ceil((redirectTime - currentTime) / 1000), true) }}...
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
<div v-else>
|
|
23
|
+
Return to <router-link to="/">index page</router-link>.
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup>
|
|
30
|
+
|
|
31
|
+
import Button from 'primevue/button'
|
|
32
|
+
|
|
33
|
+
import { onMounted, ref } from 'vue'
|
|
34
|
+
const isMounted = ref(false)
|
|
35
|
+
onMounted(() => isMounted.value = true)
|
|
36
|
+
|
|
37
|
+
import { computed } from 'vue'
|
|
38
|
+
import { currentTime } from "@live-change/frontend-base"
|
|
39
|
+
|
|
40
|
+
import { useRouter } from 'vue-router'
|
|
41
|
+
const router = useRouter()
|
|
42
|
+
|
|
43
|
+
import { usePath, live } from "@live-change/vue3-ssr"
|
|
44
|
+
|
|
45
|
+
import pluralize from 'pluralize'
|
|
46
|
+
|
|
47
|
+
const afterGoogleAccessGained = computed( () => isMounted.value && localStorage.afterGoogleAccessGained )
|
|
48
|
+
let redirectTime
|
|
49
|
+
onMounted(() => {
|
|
50
|
+
redirectTime = new Date(Date.now() + 10 * 1000)
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
if (afterGoogleAccessGained.value) {
|
|
53
|
+
localStorage.removeItem('afterGoogleAccessGained')
|
|
54
|
+
router.push(afterSignIn.value)
|
|
55
|
+
}
|
|
56
|
+
}, redirectTime - Date.now())
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const path = usePath()
|
|
60
|
+
const [ offlineAccess ] = await Promise.all([
|
|
61
|
+
live(path.googleAuthentication.myUserOfflineAccess({}))
|
|
62
|
+
])
|
|
63
|
+
|
|
64
|
+
const accessList = computed(() => offlineAccess.value.scopes.map(
|
|
65
|
+
scope => scope.split('/').pop()
|
|
66
|
+
))
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
|
|
71
|
+
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full">
|
|
3
|
+
<div class="surface-card border-round shadow-2 p-4">
|
|
4
|
+
<div class="text-900 font-medium mb-3 text-xl mb-4">Google Api Access</div>
|
|
5
|
+
<p class="mt-0 p-0 line-height-3">
|
|
6
|
+
Your current access:
|
|
7
|
+
</p>
|
|
8
|
+
<ul>
|
|
9
|
+
<li v-for="scope in currentAccess">
|
|
10
|
+
{{ scope.split('/').pop() }}
|
|
11
|
+
</li>
|
|
12
|
+
</ul>
|
|
13
|
+
<p>
|
|
14
|
+
We need access to additional scopes:
|
|
15
|
+
</p>
|
|
16
|
+
<ul>
|
|
17
|
+
<li v-for="scope in additionalScopes">
|
|
18
|
+
{{ scope.split('/').pop() }}
|
|
19
|
+
</li>
|
|
20
|
+
</ul>
|
|
21
|
+
<p>
|
|
22
|
+
Please click the button below to grant access.
|
|
23
|
+
</p>
|
|
24
|
+
<router-link
|
|
25
|
+
:to="{ name: 'user:googleAuthScopes', params: {
|
|
26
|
+
action: 'addOfflineAccessToken',
|
|
27
|
+
accessType: 'offline',
|
|
28
|
+
scopes: allScopes
|
|
29
|
+
} }">
|
|
30
|
+
<Button icon="pi pi-key" label="Google Authentication" />
|
|
31
|
+
</router-link>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup>
|
|
38
|
+
|
|
39
|
+
import Button from 'primevue/button'
|
|
40
|
+
|
|
41
|
+
import { onMounted, ref } from 'vue'
|
|
42
|
+
const isMounted = ref(false)
|
|
43
|
+
onMounted(() => isMounted.value = true)
|
|
44
|
+
|
|
45
|
+
import { computed, toRefs } from 'vue'
|
|
46
|
+
import { usePath, live } from "@live-change/vue3-ssr"
|
|
47
|
+
|
|
48
|
+
const props = defineProps({
|
|
49
|
+
scopes: {
|
|
50
|
+
type: Array,
|
|
51
|
+
required: true
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
const { scopes } = toRefs(props)
|
|
55
|
+
|
|
56
|
+
const path = usePath()
|
|
57
|
+
const [ offlineAccess ] = await Promise.all([
|
|
58
|
+
live(path.googleAuthentication.myUserOfflineAccess({}))
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
const currentAccess = computed(() => offlineAccess.value.scopes)
|
|
62
|
+
const additionalScopes = computed(() => scopes.value.filter(
|
|
63
|
+
scope => !currentAccess.value.includes(scope)
|
|
64
|
+
))
|
|
65
|
+
|
|
66
|
+
const allScopes = computed(() => [...currentAccess.value, ...additionalScopes.value])
|
|
67
|
+
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<style>
|
|
71
|
+
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function routes(config = {}) {
|
|
2
|
+
const { prefix = '/', route = (r) => r } = config
|
|
3
|
+
|
|
4
|
+
return [
|
|
5
|
+
|
|
6
|
+
route({ name: 'user:google-access-gained', path: prefix + 'google-offline-access-gained',
|
|
7
|
+
component: () => import("./AccessGained.vue"), meta: { signedIn: true } }),
|
|
8
|
+
|
|
9
|
+
route({ name: 'user:get-google-access', path: prefix + 'get-google-access/:scopes*',
|
|
10
|
+
component: () => import("./GetAccess.vue"), meta: { signedIn: true }, props: true }),
|
|
11
|
+
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default routes
|
package/front/src/router.js
CHANGED
|
@@ -9,6 +9,7 @@ import signRoutes from "./sign/routes.js"
|
|
|
9
9
|
import connectedRoutes from "./connected/routes.js"
|
|
10
10
|
import identificationRoutes from "./identification/routes.js"
|
|
11
11
|
import deleteRoutes from "./delete/routes.js"
|
|
12
|
+
import googleAccessRoutes from "./google-access/routes.js"
|
|
12
13
|
import { passwordResetRoutes, passwordChangeRoutes } from "./password/routes.js"
|
|
13
14
|
import { notificationsSettingsRoutes, notificationsRoutes } from "./notifications/routes.js"
|
|
14
15
|
import localeSettingsRoutes from "./locale/routes.js"
|
|
@@ -23,6 +24,7 @@ export function userRoutes(config = {}) {
|
|
|
23
24
|
...signRoutes(config),
|
|
24
25
|
...passwordResetRoutes(config),
|
|
25
26
|
...notificationsRoutes(config),
|
|
27
|
+
...googleAccessRoutes(config),
|
|
26
28
|
|
|
27
29
|
route({
|
|
28
30
|
path: prefix + 'settings', meta: { pageType: 'wide' },
|
|
@@ -87,7 +89,7 @@ export function createRouter(app, config) {
|
|
|
87
89
|
history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
|
|
88
90
|
routes: [
|
|
89
91
|
{ name: 'index', path: '/', component: () => import('./Index.vue') },
|
|
90
|
-
...userRoutes(config),
|
|
92
|
+
...userRoutes({ ...config, prefix: '/user/' }),
|
|
91
93
|
...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) })
|
|
92
94
|
]
|
|
93
95
|
})
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
16
16
|
<div v-else-if="state === 'waiting'" class="text-center">
|
|
17
|
-
Authentication will open in
|
|
17
|
+
Authentication will open in this window.
|
|
18
18
|
</div>
|
|
19
19
|
<div v-else-if="state === 'working'" class="text-center">
|
|
20
20
|
Waiting for server...
|
|
21
21
|
</div>
|
|
22
22
|
<div v-else-if="state === 'error'" class="text-center">
|
|
23
|
-
<div>Error during authentication
|
|
23
|
+
<div>Error during authentication:</div>
|
|
24
24
|
<div>{{ error }}</div>
|
|
25
25
|
</div>
|
|
26
26
|
<div v-else>
|
|
@@ -32,79 +32,53 @@
|
|
|
32
32
|
</template>
|
|
33
33
|
|
|
34
34
|
<script setup>
|
|
35
|
-
import { loadGoogleAuth2 } from "../utils/googleApi.js"
|
|
36
35
|
import { defineProps, toRefs, ref, onMounted, inject } from 'vue'
|
|
37
36
|
|
|
38
|
-
import {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
import { useToast } from 'primevue/usetoast'
|
|
42
|
-
const toast = useToast()
|
|
37
|
+
import { useRouter } from 'vue-router'
|
|
38
|
+
const router = useRouter()
|
|
43
39
|
|
|
44
40
|
const workingZone = inject('workingZone')
|
|
45
41
|
|
|
46
|
-
import {
|
|
47
|
-
const router = useRouter()
|
|
42
|
+
import { googleAuthRedirect } from '../utils/googleAuth.js'
|
|
48
43
|
|
|
49
44
|
const props = defineProps({
|
|
50
45
|
action: {
|
|
51
46
|
type: String,
|
|
52
47
|
default: 'signInOrSignUp'
|
|
48
|
+
},
|
|
49
|
+
accessType: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: 'offline', //'online'
|
|
52
|
+
},
|
|
53
|
+
scopes: {
|
|
54
|
+
type: Array,
|
|
55
|
+
default: () => ['profile', 'email']
|
|
53
56
|
}
|
|
54
57
|
})
|
|
55
58
|
|
|
56
|
-
const { action } = toRefs(props)
|
|
59
|
+
const { action, accessType, scopes } = toRefs(props)
|
|
57
60
|
const state = ref('waiting')
|
|
58
61
|
const error = ref(null)
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
function googleAuth() {
|
|
61
64
|
state.value = 'waiting'
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
scope: 'profile email',
|
|
71
|
-
ux_mode: 'redirect',
|
|
72
|
-
redirect_uri: googleRedirectUri
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
if(error.error === 'popup_closed_by_user') {
|
|
76
|
-
toast.add({ severity: 'warning', summary: 'Canceled', detail: 'You closed login window', life: 3000 })
|
|
77
|
-
state.value = 'canceled'
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
throw error
|
|
65
|
+
|
|
66
|
+
workingZone.addPromise('google auth', new Promise((resolve, reject) => {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
state.value = 'error'
|
|
69
|
+
error.value = 'redirect_timeout'
|
|
70
|
+
// return reject('redirect timeout?!')
|
|
71
|
+
return resolve()
|
|
72
|
+
}, 4000)
|
|
81
73
|
}))
|
|
82
74
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//console.log("GAUTH RESULT", result)
|
|
91
|
-
const { action: actionDone, user } = result
|
|
92
|
-
while(api.client.value.user !== result.user) {
|
|
93
|
-
await new Promise(resolve => setTimeout(resolve, 100))
|
|
94
|
-
}
|
|
95
|
-
if(actionDone === 'signIn') {
|
|
96
|
-
router.push({ name: 'user:signInFinished' })
|
|
97
|
-
} else if(actionDone === 'signUp') {
|
|
98
|
-
router.push({ name: 'user:signUpFinished' })
|
|
99
|
-
} else {
|
|
100
|
-
console.error("Unknown action", actionDone)
|
|
101
|
-
}
|
|
102
|
-
} catch(error) {
|
|
103
|
-
console.error("Google auth error", error)
|
|
104
|
-
toast.add({ severity: 'error', summary: 'Error', detail: 'Error during google authentication', life: 3000 })
|
|
105
|
-
state.value = 'error'
|
|
106
|
-
error.value = error
|
|
107
|
-
}
|
|
75
|
+
googleAuthRedirect({
|
|
76
|
+
scope: scopes.value.join(' '),
|
|
77
|
+
redirectUri: document.location.protocol + '//' + document.location.host
|
|
78
|
+
+ router.resolve({ name: 'user:googleAuthReturn', params: { action: action.value } }).href,
|
|
79
|
+
accessType: accessType.value
|
|
80
|
+
})
|
|
81
|
+
|
|
108
82
|
}
|
|
109
83
|
|
|
110
84
|
async function back() {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
<div v-if="state === 'canceled'" class="text-center">
|
|
10
10
|
<div>Authentication canceled by user</div>
|
|
11
11
|
<div class="flex flex-row">
|
|
12
|
-
<Button @click="back" label="Go back" icon="pi pi-arrow-left"
|
|
12
|
+
<Button @click="back" label="Go back" icon="pi pi-arrow-left"
|
|
13
|
+
class="w-full p-button-secondary mb-1" />
|
|
13
14
|
</div>
|
|
14
15
|
</div>
|
|
15
16
|
<div v-else-if="state === 'working'" class="text-center">
|
|
@@ -28,7 +29,6 @@
|
|
|
28
29
|
</template>
|
|
29
30
|
|
|
30
31
|
<script setup>
|
|
31
|
-
import { loadGoogleAuth2 } from "../utils/googleApi.js"
|
|
32
32
|
import { defineProps, toRefs, ref, onMounted, inject } from 'vue'
|
|
33
33
|
|
|
34
34
|
import { useApi } from "@live-change/vue3-ssr"
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
|
|
40
40
|
const workingZone = inject('workingZone')
|
|
41
41
|
|
|
42
|
-
import { useRouter } from 'vue-router'
|
|
42
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
43
43
|
const router = useRouter()
|
|
44
|
+
const route = useRoute()
|
|
44
45
|
|
|
45
46
|
const props = defineProps({
|
|
46
47
|
action: {
|
|
@@ -53,29 +54,25 @@
|
|
|
53
54
|
const state = ref('waiting')
|
|
54
55
|
const error = ref(null)
|
|
55
56
|
|
|
56
|
-
|
|
57
57
|
onMounted(async () => {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.map(p => p.split('='))
|
|
63
|
-
.find(a => a[0] === 'id_token')
|
|
64
|
-
[1]
|
|
65
|
-
)
|
|
66
|
-
if(!id_token) {
|
|
58
|
+
const query = route.query
|
|
59
|
+
console.log("QUERY", query)
|
|
60
|
+
|
|
61
|
+
if(!query.code) {
|
|
67
62
|
state.value = 'canceled'
|
|
68
63
|
return
|
|
69
64
|
}
|
|
70
65
|
try {
|
|
71
66
|
const result = await workingZone.addPromise(`google ${action.value}`,
|
|
72
67
|
api.command(['googleAuthentication', action.value], {
|
|
73
|
-
|
|
68
|
+
redirectUri: document.location.protocol + '//' + document.location.host
|
|
69
|
+
+ router.resolve({ name: 'user:googleAuthReturn', params: { action: action.value } }).href,
|
|
70
|
+
...query
|
|
74
71
|
})
|
|
75
72
|
)
|
|
76
73
|
console.log("GAUTH RESULT", result)
|
|
77
74
|
const { action: actionDone, user } = result
|
|
78
|
-
while(api.client.value.user !==
|
|
75
|
+
while(user && api.client.value.user !== user) {
|
|
79
76
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
80
77
|
}
|
|
81
78
|
if(actionDone === 'signIn') {
|
|
@@ -84,6 +81,8 @@
|
|
|
84
81
|
router.push({ name: 'user:signUpFinished' })
|
|
85
82
|
} else if(actionDone === 'connectGoogle') {
|
|
86
83
|
router.push({ name: 'user:connected' })
|
|
84
|
+
} else if(actionDone === 'addOfflineAccessToken') {
|
|
85
|
+
router.push({ name: 'user:google-access-gained' })
|
|
87
86
|
} else {
|
|
88
87
|
console.error("Unknown action", actionDone)
|
|
89
88
|
}
|
package/front/src/sign/routes.js
CHANGED
|
@@ -5,6 +5,8 @@ export function routes(config = {}) {
|
|
|
5
5
|
|
|
6
6
|
route({ name: 'user:googleAuth', path: prefix + 'google-auth/:action',
|
|
7
7
|
component: () => import("./GoogleAuth.vue"), props: true, meta: { } }),
|
|
8
|
+
route({ name: 'user:googleAuthScopes', path: prefix + 'google-auth/:action/:scopes*',
|
|
9
|
+
component: () => import("./GoogleAuth.vue"), props: true, meta: { } }),
|
|
8
10
|
route({ name: 'user:googleAuthReturn', path: prefix + 'google-auth-return/:action',
|
|
9
11
|
component: () => import("./GoogleAuthReturn.vue"), props: true }),
|
|
10
12
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function getAuthorizationUri(config) {
|
|
2
|
+
const {
|
|
3
|
+
authorizationBase = 'https://accounts.google.com/o/oauth2/auth',
|
|
4
|
+
accessType = 'offline',
|
|
5
|
+
approvalPrompt = 'force',
|
|
6
|
+
scope,
|
|
7
|
+
responseType = 'code',
|
|
8
|
+
clientId = ENV_GOOGLE_CLIENT_ID,
|
|
9
|
+
redirectUri = 'urn:ietf:wg:oauth:2.0:oob',
|
|
10
|
+
} = config
|
|
11
|
+
|
|
12
|
+
const authorizationUri = authorizationBase +
|
|
13
|
+
`?access_type=${accessType}&approval_prompt=${approvalPrompt}` +
|
|
14
|
+
`&scope=${encodeURIComponent(scope)}&response_type=${responseType}`+
|
|
15
|
+
`&client_id=${encodeURIComponent(clientId)}`+
|
|
16
|
+
//`&state=${encodeURIComponent(clientId)}` +
|
|
17
|
+
`&redirect_uri=${encodeURIComponent(redirectUri)}`
|
|
18
|
+
|
|
19
|
+
return authorizationUri
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function googleAuthRedirect(opts) {
|
|
23
|
+
const authUri = getAuthorizationUri({
|
|
24
|
+
...opts
|
|
25
|
+
})
|
|
26
|
+
console.log("AUTH URI", authUri)
|
|
27
|
+
|
|
28
|
+
setTimeout(() => window.location = authUri, 100)
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/user-frontend",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.35",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "node --inspect --expose-gc server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "rm tmp.db; node server/start.js localDev --enableSessions --initScript ./init.js",
|
|
@@ -22,30 +22,30 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@live-change/cli": "^0.8.
|
|
26
|
-
"@live-change/dao": "^0.8.
|
|
27
|
-
"@live-change/dao-vue3": "^0.8.
|
|
28
|
-
"@live-change/dao-websocket": "^0.8.
|
|
29
|
-
"@live-change/email-service": "^0.8.
|
|
30
|
-
"@live-change/framework": "^0.8.
|
|
31
|
-
"@live-change/identicon-service": "^0.8.
|
|
32
|
-
"@live-change/image-frontend": "^0.8.
|
|
33
|
-
"@live-change/message-authentication-service": "^0.8.
|
|
34
|
-
"@live-change/notification-service": "^0.8.
|
|
35
|
-
"@live-change/password-authentication-service": "^0.8.
|
|
36
|
-
"@live-change/pattern": "^0.8.
|
|
37
|
-
"@live-change/secret-code-service": "^0.8.
|
|
38
|
-
"@live-change/secret-link-service": "^0.8.
|
|
39
|
-
"@live-change/security-frontend": "^0.8.
|
|
40
|
-
"@live-change/security-service": "^0.8.
|
|
41
|
-
"@live-change/session-service": "^0.8.
|
|
42
|
-
"@live-change/timer-service": "^0.8.
|
|
43
|
-
"@live-change/upload-service": "^0.8.
|
|
44
|
-
"@live-change/user-identification-service": "^0.8.
|
|
45
|
-
"@live-change/user-service": "^0.8.
|
|
46
|
-
"@live-change/vue3-components": "^0.8.
|
|
47
|
-
"@live-change/vue3-ssr": "^0.8.
|
|
48
|
-
"@vueuse/core": "^10.
|
|
25
|
+
"@live-change/cli": "^0.8.35",
|
|
26
|
+
"@live-change/dao": "^0.8.35",
|
|
27
|
+
"@live-change/dao-vue3": "^0.8.35",
|
|
28
|
+
"@live-change/dao-websocket": "^0.8.35",
|
|
29
|
+
"@live-change/email-service": "^0.8.35",
|
|
30
|
+
"@live-change/framework": "^0.8.35",
|
|
31
|
+
"@live-change/identicon-service": "^0.8.35",
|
|
32
|
+
"@live-change/image-frontend": "^0.8.35",
|
|
33
|
+
"@live-change/message-authentication-service": "^0.8.35",
|
|
34
|
+
"@live-change/notification-service": "^0.8.35",
|
|
35
|
+
"@live-change/password-authentication-service": "^0.8.35",
|
|
36
|
+
"@live-change/pattern": "^0.8.35",
|
|
37
|
+
"@live-change/secret-code-service": "^0.8.35",
|
|
38
|
+
"@live-change/secret-link-service": "^0.8.35",
|
|
39
|
+
"@live-change/security-frontend": "^0.8.35",
|
|
40
|
+
"@live-change/security-service": "^0.8.35",
|
|
41
|
+
"@live-change/session-service": "^0.8.35",
|
|
42
|
+
"@live-change/timer-service": "^0.8.35",
|
|
43
|
+
"@live-change/upload-service": "^0.8.35",
|
|
44
|
+
"@live-change/user-identification-service": "^0.8.35",
|
|
45
|
+
"@live-change/user-service": "^0.8.35",
|
|
46
|
+
"@live-change/vue3-components": "^0.8.35",
|
|
47
|
+
"@live-change/vue3-ssr": "^0.8.35",
|
|
48
|
+
"@vueuse/core": "^10.11.0",
|
|
49
49
|
"codeceptjs-assert": "^0.0.5",
|
|
50
50
|
"codeceptjs-video-helper": "0.1.3",
|
|
51
51
|
"compression": "^1.7.4",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"unique-names-generator": "4.7.1",
|
|
61
61
|
"v-shared-element": "3.1.1",
|
|
62
62
|
"vue-meta": "^3.0.0-alpha.9",
|
|
63
|
-
"vue-router": "^4.
|
|
63
|
+
"vue-router": "^4.3.3",
|
|
64
64
|
"vue3-scroll-border": "0.1.6",
|
|
65
65
|
"wtfnode": "^0.9.1"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@live-change/codeceptjs-helper": "^0.8.
|
|
68
|
+
"@live-change/codeceptjs-helper": "^0.8.35",
|
|
69
69
|
"codeceptjs": "^3.5.12",
|
|
70
70
|
"generate-password": "1.7.1",
|
|
71
71
|
"playwright": "^1.41.2",
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
77
77
|
"license": "BSD-3-Clause",
|
|
78
78
|
"description": "",
|
|
79
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "90fbb746dc7270895daf17b437ca48c0b0a01c01"
|
|
80
80
|
}
|
package/server/app.config.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import App from "@live-change/framework"
|
|
2
2
|
const app = App.app()
|
|
3
3
|
|
|
4
|
+
import dotenv from 'dotenv'
|
|
5
|
+
dotenv.config()
|
|
6
|
+
|
|
4
7
|
const contactTypes = ['email', 'phone']
|
|
5
8
|
const remoteAccountTypes = ['google']
|
|
6
9
|
|
|
@@ -86,11 +89,11 @@ app.config = {
|
|
|
86
89
|
name: 'image',
|
|
87
90
|
path: '@live-change/image-service'
|
|
88
91
|
},
|
|
89
|
-
{
|
|
92
|
+
/* {
|
|
90
93
|
name: 'backup',
|
|
91
94
|
path: '@live-change/backup-service',
|
|
92
95
|
clearEvents: true
|
|
93
|
-
}
|
|
96
|
+
}*/
|
|
94
97
|
|
|
95
98
|
// { path: '@live-change/google-account-service' },
|
|
96
99
|
]
|
package/server/services.list.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import timer from '@live-change/timer-service'
|
|
1
2
|
import session from '@live-change/session-service'
|
|
2
3
|
import user from '@live-change/user-service'
|
|
3
4
|
import email from '@live-change/email-service'
|
|
@@ -15,10 +16,11 @@ import secretLink from '@live-change/secret-link-service'
|
|
|
15
16
|
import messageAuthentication from '@live-change/message-authentication-service'
|
|
16
17
|
import googleAuthentication from '@live-change/google-authentication-service'
|
|
17
18
|
|
|
18
|
-
import backup from '@live-change/backup-service'
|
|
19
|
+
//import backup from '@live-change/backup-service'
|
|
19
20
|
import init from './init.js'
|
|
20
21
|
|
|
21
22
|
export {
|
|
23
|
+
timer,
|
|
22
24
|
session,
|
|
23
25
|
user,
|
|
24
26
|
email,
|
|
@@ -35,6 +37,6 @@ export {
|
|
|
35
37
|
messageAuthentication,
|
|
36
38
|
googleAuthentication,
|
|
37
39
|
localeSettings,
|
|
38
|
-
backup,
|
|
40
|
+
// backup,
|
|
39
41
|
init
|
|
40
42
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
let googPromise
|
|
2
|
-
|
|
3
|
-
function loadGoogle() {
|
|
4
|
-
if(googPromise) return googPromise
|
|
5
|
-
let resolved = false
|
|
6
|
-
googPromise = new Promise((resolve, reject) => {
|
|
7
|
-
if (typeof window != 'undefined') {
|
|
8
|
-
window.googAsyncInit = function () {
|
|
9
|
-
if(resolved) return
|
|
10
|
-
resolved = true
|
|
11
|
-
resolve(gapi)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
;(function (d, s, id) {
|
|
15
|
-
const fjs = d.getElementsByTagName(s)[0]
|
|
16
|
-
if (d.getElementById(id)) return
|
|
17
|
-
const js = d.createElement(s)
|
|
18
|
-
js.id = id
|
|
19
|
-
js.src = "https://apis.google.com/js/platform.js?onload=googAsyncInit"
|
|
20
|
-
fjs.parentNode.insertBefore(js, fjs)
|
|
21
|
-
}(document, 'script', 'google-jssdk'))
|
|
22
|
-
} else {
|
|
23
|
-
reject('unavailable')
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
return googPromise
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let googAuth2Promise
|
|
30
|
-
|
|
31
|
-
async function loadGoogleAuth2() {
|
|
32
|
-
if(googAuth2Promise) return googAuth2Promise
|
|
33
|
-
let gapi = await loadGoogle()
|
|
34
|
-
let resolved = false
|
|
35
|
-
googAuth2Promise = new Promise((resolve, reject) => {
|
|
36
|
-
gapi.load('auth2', function() {
|
|
37
|
-
if(resolved) return
|
|
38
|
-
resolved = true
|
|
39
|
-
let client_id = ENV_GOOGLE_CLIENT_ID
|
|
40
|
-
resolve(gapi.auth2.init({
|
|
41
|
-
client_id
|
|
42
|
-
}))
|
|
43
|
-
})
|
|
44
|
-
})
|
|
45
|
-
return googAuth2Promise
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export { loadGoogle, loadGoogleAuth2 }
|