@libreapps/auth 3.0.1
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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE.md +21 -0
- package/README.md +61 -0
- package/components/auth-widget.tsx +110 -0
- package/components/email-password-form.tsx +96 -0
- package/components/index.ts +4 -0
- package/components/login-panel.tsx +207 -0
- package/components/signup-panel.tsx +213 -0
- package/dist/components/auth-widget.d.ts +13 -0
- package/dist/components/auth-widget.js +33 -0
- package/dist/components/auth-widget.js.map +1 -0
- package/dist/components/email-password-form.d.ts +8 -0
- package/dist/components/email-password-form.js +25 -0
- package/dist/components/email-password-form.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/login-panel.d.ts +13 -0
- package/dist/components/login-panel.js +104 -0
- package/dist/components/login-panel.js.map +1 -0
- package/dist/components/signup-panel.d.ts +13 -0
- package/dist/components/signup-panel.js +104 -0
- package/dist/components/signup-panel.js.map +1 -0
- package/dist/icons/ethereum.d.ts +4 -0
- package/dist/icons/ethereum.js +6 -0
- package/dist/icons/ethereum.js.map +1 -0
- package/dist/icons/facebook.d.ts +4 -0
- package/dist/icons/facebook.js +6 -0
- package/dist/icons/facebook.js.map +1 -0
- package/dist/icons/github.d.ts +4 -0
- package/dist/icons/github.js +6 -0
- package/dist/icons/github.js.map +1 -0
- package/dist/icons/google.d.ts +4 -0
- package/dist/icons/google.js +6 -0
- package/dist/icons/google.js.map +1 -0
- package/dist/icons/index.d.ts +6 -0
- package/dist/icons/index.js +7 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/server/firebase-support.d.ts +8 -0
- package/dist/server/firebase-support.js +151 -0
- package/dist/server/firebase-support.js.map +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/rest-api-handlers.d.ts +4 -0
- package/dist/server/rest-api-handlers.js +23 -0
- package/dist/server/rest-api-handlers.js.map +1 -0
- package/dist/server/stub-server.d.ts +14 -0
- package/dist/server/stub-server.js +23 -0
- package/dist/server/stub-server.js.map +1 -0
- package/dist/service/auth-service.d.ts +29 -0
- package/dist/service/auth-service.js +2 -0
- package/dist/service/auth-service.js.map +1 -0
- package/dist/service/context.d.ts +9 -0
- package/dist/service/context.js +16 -0
- package/dist/service/context.js.map +1 -0
- package/dist/service/get-singleton.d.ts +4 -0
- package/dist/service/get-singleton.js +24 -0
- package/dist/service/get-singleton.js.map +1 -0
- package/dist/service/impl/firebase-support.d.ts +34 -0
- package/dist/service/impl/firebase-support.js +190 -0
- package/dist/service/impl/firebase-support.js.map +1 -0
- package/dist/service/impl/index.d.ts +32 -0
- package/dist/service/impl/index.js +179 -0
- package/dist/service/impl/index.js.map +1 -0
- package/dist/service/impl/stub-auth-service.d.ts +42 -0
- package/dist/service/impl/stub-auth-service.js +97 -0
- package/dist/service/impl/stub-auth-service.js.map +1 -0
- package/dist/service/impl/wallet-support.d.ts +8 -0
- package/dist/service/impl/wallet-support.js +82 -0
- package/dist/service/impl/wallet-support.js.map +1 -0
- package/dist/service/index.d.ts +4 -0
- package/dist/service/index.js +4 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/provider-registry.d.ts +37 -0
- package/dist/service/provider-registry.js +58 -0
- package/dist/service/provider-registry.js.map +1 -0
- package/dist/types/api-response.d.ts +8 -0
- package/dist/types/api-response.js +2 -0
- package/dist/types/api-response.js.map +1 -0
- package/dist/types/auth-service-conf.d.ts +5 -0
- package/dist/types/auth-service-conf.js +2 -0
- package/dist/types/auth-service-conf.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/libreapps-user-info-value.d.ts +6 -0
- package/dist/types/libreapps-user-info-value.js +2 -0
- package/dist/types/libreapps-user-info-value.js.map +1 -0
- package/dist/types/libreapps-user-info.d.ts +6 -0
- package/dist/types/libreapps-user-info.js +2 -0
- package/dist/types/libreapps-user-info.js.map +1 -0
- package/dist/util/analytics.d.ts +9 -0
- package/dist/util/analytics.js +10 -0
- package/dist/util/analytics.js.map +1 -0
- package/icons/ethereum.tsx +18 -0
- package/icons/facebook.tsx +11 -0
- package/icons/github.tsx +14 -0
- package/icons/google.tsx +13 -0
- package/icons/index.ts +16 -0
- package/index.ts +51 -0
- package/libreapps-ui.d.ts +23 -0
- package/package.json +57 -0
- package/server/firebase-support.ts +176 -0
- package/server/index.ts +14 -0
- package/server/rest-api-handlers.ts +33 -0
- package/server/stub-server.ts +28 -0
- package/service/auth-service.ts +21 -0
- package/service/context.tsx +46 -0
- package/service/get-singleton.ts +37 -0
- package/service/impl/firebase-support.ts +241 -0
- package/service/impl/index.ts +231 -0
- package/service/impl/stub-auth-service.ts +131 -0
- package/service/impl/wallet-support.ts +100 -0
- package/service/index.ts +11 -0
- package/service/provider-registry.ts +71 -0
- package/tsconfig.json +15 -0
- package/types/api-response.ts +5 -0
- package/types/auth-service-conf.ts +9 -0
- package/types/index.ts +6 -0
- package/types/libreapps-user-info-value.ts +9 -0
- package/types/libreapps-user-info.ts +9 -0
- package/util/analytics.ts +21 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cookies } from 'next/headers'
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
3
|
+
import { createSessionCookie, revokeAllSessions } from './firebase-support'
|
|
4
|
+
import type { APIResponse } from '../types'
|
|
5
|
+
|
|
6
|
+
export async function handleLogin(request: NextRequest) {
|
|
7
|
+
const reqBody = (await request.json()) as { idToken: string }
|
|
8
|
+
const idToken = reqBody.idToken
|
|
9
|
+
|
|
10
|
+
const expiresIn = 60 * 60 * 24 * 5 * 1000 // 5 days
|
|
11
|
+
|
|
12
|
+
const sessionCookie = await createSessionCookie(idToken, { expiresIn })
|
|
13
|
+
|
|
14
|
+
const c = await cookies()
|
|
15
|
+
c.set('__session', sessionCookie, { maxAge: expiresIn, httpOnly: true, secure: true })
|
|
16
|
+
|
|
17
|
+
return NextResponse.json<APIResponse<string>>({ success: true, data: 'Signed in successfully.' })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function handleLogout() {
|
|
21
|
+
const c = await cookies()
|
|
22
|
+
const sessionCookie = c.get('__session')?.value
|
|
23
|
+
|
|
24
|
+
if (!sessionCookie) {
|
|
25
|
+
return NextResponse.json<APIResponse<string>>({ success: false, error: 'Session not found.' }, { status: 400 })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
c.delete('__session')
|
|
29
|
+
|
|
30
|
+
await revokeAllSessions(sessionCookie)
|
|
31
|
+
|
|
32
|
+
return NextResponse.json<APIResponse<string>>({ success: true, data: 'Signed out successfully.' })
|
|
33
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stub Server-side Authentication
|
|
3
|
+
*
|
|
4
|
+
* Used when Firebase Admin is not configured.
|
|
5
|
+
* All functions return null/false gracefully.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { LibreAppsUserInfoValue } from '../types'
|
|
9
|
+
|
|
10
|
+
export async function getUserServerSide(): Promise<LibreAppsUserInfoValue | null> {
|
|
11
|
+
console.warn('Server-side auth not configured. Install @libreapps/auth-firebase for Firebase support.')
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function generateCustomToken(): Promise<{success: boolean, token: string | null}> {
|
|
16
|
+
console.warn('Server-side auth not configured. Install @libreapps/auth-firebase for Firebase support.')
|
|
17
|
+
return { success: false, token: null }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function createSessionCookie(_idToken: string, _sessionCookieOptions: any): Promise<string> {
|
|
21
|
+
console.warn('Server-side auth not configured. Install @libreapps/auth-firebase for Firebase support.')
|
|
22
|
+
throw new Error('Auth provider not configured')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function revokeAllSessions(_session: string): Promise<void> {
|
|
26
|
+
console.warn('Server-side auth not configured. Install @libreapps/auth-firebase for Firebase support.')
|
|
27
|
+
throw new Error('Auth provider not configured')
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LibreAppsUserInfo } from "../types"
|
|
2
|
+
|
|
3
|
+
type AuthProvider = 'google' | 'facebook' | 'github'
|
|
4
|
+
|
|
5
|
+
interface AuthService {
|
|
6
|
+
|
|
7
|
+
get loggedIn(): boolean
|
|
8
|
+
get user(): LibreAppsUserInfo | null // returns current info obj // all fields observable :)
|
|
9
|
+
|
|
10
|
+
signupEmailAndPassword: ( email: string, password: string ) => Promise<{success: boolean, userInfo: LibreAppsUserInfo | null, message?: string}>
|
|
11
|
+
loginEmailAndPassword: ( email: string, password: string ) => Promise<{success: boolean, userInfo: LibreAppsUserInfo | null, message?: string}>
|
|
12
|
+
loginWithProvider: ( provider: AuthProvider ) => Promise<{success: boolean, userInfo: LibreAppsUserInfo | null}>
|
|
13
|
+
loginWithCustomToken: ( token: string ) => Promise<{success: boolean, userInfo: LibreAppsUserInfo | null}>
|
|
14
|
+
associateWallet: () => Promise<void>
|
|
15
|
+
logout: () => Promise<{success: boolean}>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
type AuthService as default,
|
|
20
|
+
type AuthProvider
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, {
|
|
4
|
+
useContext,
|
|
5
|
+
type PropsWithChildren
|
|
6
|
+
} from 'react'
|
|
7
|
+
|
|
8
|
+
import type { AuthServiceConf, LibreAppsUserInfoValue} from '../types'
|
|
9
|
+
import type AuthService from './auth-service'
|
|
10
|
+
import getSingleton from './get-singleton'
|
|
11
|
+
|
|
12
|
+
const AuthServiceContext = React.createContext<AuthService | undefined>(undefined)
|
|
13
|
+
|
|
14
|
+
/* PLEASE LEAVE
|
|
15
|
+
const _log = (s: string) => {
|
|
16
|
+
const d = new Date()
|
|
17
|
+
console.log(`TIMESTAMPED: ${d.getUTCMinutes()}:${d.getUTCSeconds()}:${d.getUTCMilliseconds()}`)
|
|
18
|
+
console.log(s)
|
|
19
|
+
}
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const useAuth = (): AuthService => (
|
|
23
|
+
useContext(AuthServiceContext) as AuthService
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
const AuthServiceProvider: React.FC<
|
|
27
|
+
PropsWithChildren & {
|
|
28
|
+
conf: AuthServiceConf
|
|
29
|
+
user: LibreAppsUserInfoValue | null
|
|
30
|
+
}
|
|
31
|
+
> = ({
|
|
32
|
+
children,
|
|
33
|
+
user,
|
|
34
|
+
conf
|
|
35
|
+
}) => (
|
|
36
|
+
<AuthServiceContext.Provider value={getSingleton(conf, user)}>
|
|
37
|
+
{children}
|
|
38
|
+
</AuthServiceContext.Provider>
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
AuthServiceProvider,
|
|
44
|
+
useAuth
|
|
45
|
+
}
|
|
46
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { enableStaticRendering } from 'mobx-react-lite'
|
|
2
|
+
|
|
3
|
+
import type AuthService from './auth-service'
|
|
4
|
+
import type { AuthServiceConf, LibreAppsUserInfoValue } from '../types'
|
|
5
|
+
import { getActiveProvider } from './provider-registry'
|
|
6
|
+
import { StubAuthService } from './impl/stub-auth-service'
|
|
7
|
+
|
|
8
|
+
enableStaticRendering(typeof window === "undefined")
|
|
9
|
+
|
|
10
|
+
// https://dev.to/ivandotv/mobx-server-side-rendering-with-next-js-4m18
|
|
11
|
+
let instance: AuthService | undefined = undefined
|
|
12
|
+
|
|
13
|
+
const getSingleton = (
|
|
14
|
+
conf: AuthServiceConf,
|
|
15
|
+
serverSideUser: LibreAppsUserInfoValue | null
|
|
16
|
+
): AuthService => {
|
|
17
|
+
|
|
18
|
+
// Get the registered auth provider, or use stub if none configured
|
|
19
|
+
const AuthServiceClass = getActiveProvider() ?? StubAuthService
|
|
20
|
+
|
|
21
|
+
// For server side rendering always create a new store
|
|
22
|
+
if (typeof window === "undefined") {
|
|
23
|
+
return new AuthServiceClass(conf, serverSideUser)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Client side, create the store only once in the client
|
|
27
|
+
if (!instance) {
|
|
28
|
+
instance = new AuthServiceClass(conf, serverSideUser)
|
|
29
|
+
}
|
|
30
|
+
else if ('setServerSideUser' in instance && typeof instance.setServerSideUser === 'function') {
|
|
31
|
+
instance.setServerSideUser(serverSideUser)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return instance
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default getSingleton
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
|
|
2
|
+
import {
|
|
3
|
+
FacebookAuthProvider,
|
|
4
|
+
GoogleAuthProvider,
|
|
5
|
+
GithubAuthProvider,
|
|
6
|
+
signInWithPopup,
|
|
7
|
+
createUserWithEmailAndPassword,
|
|
8
|
+
type User,
|
|
9
|
+
signInWithEmailAndPassword,
|
|
10
|
+
signInWithCustomToken,
|
|
11
|
+
type Auth,
|
|
12
|
+
} from 'firebase/auth'
|
|
13
|
+
|
|
14
|
+
import { initializeApp, getApps, FirebaseError, type FirebaseApp } from "firebase/app"
|
|
15
|
+
import { getAuth } from "firebase/auth"
|
|
16
|
+
import { getFirestore, type Firestore } from 'firebase/firestore'
|
|
17
|
+
|
|
18
|
+
import type APIResponse from '../../types/api-response'
|
|
19
|
+
|
|
20
|
+
export const firebaseConfig = {
|
|
21
|
+
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
|
22
|
+
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
|
23
|
+
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
|
24
|
+
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
|
25
|
+
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
|
26
|
+
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check if Firebase is configured
|
|
30
|
+
const isFirebaseConfigured = () => {
|
|
31
|
+
return firebaseConfig.apiKey && firebaseConfig.projectId
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Initialize Firebase only if configured
|
|
35
|
+
let firebaseApp: FirebaseApp | null = null
|
|
36
|
+
let auth: Auth | null = null
|
|
37
|
+
let db: Firestore | null = null
|
|
38
|
+
|
|
39
|
+
if (isFirebaseConfigured()) {
|
|
40
|
+
firebaseApp = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0]
|
|
41
|
+
auth = getAuth(firebaseApp)
|
|
42
|
+
db = getFirestore(firebaseApp, 'accounts')
|
|
43
|
+
} else {
|
|
44
|
+
console.warn('Firebase is not configured. Auth features will not work.')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { auth, db }
|
|
48
|
+
|
|
49
|
+
export async function loginWithProvider(provider: string): Promise<{ success: boolean, user: User | null }> {
|
|
50
|
+
if (!auth) {
|
|
51
|
+
console.warn('Firebase auth not configured')
|
|
52
|
+
return { success: false, user: null }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const authProvider = (() => {
|
|
56
|
+
switch (provider) {
|
|
57
|
+
case 'google':
|
|
58
|
+
return new GoogleAuthProvider()
|
|
59
|
+
case 'facebook':
|
|
60
|
+
return new FacebookAuthProvider()
|
|
61
|
+
case 'github':
|
|
62
|
+
return new GithubAuthProvider()
|
|
63
|
+
default:
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
})()
|
|
67
|
+
|
|
68
|
+
if (!authProvider) {
|
|
69
|
+
return { success: false, user: null }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const userCreds = await signInWithPopup(auth, authProvider)
|
|
74
|
+
const idToken = await userCreds.user.getIdToken()
|
|
75
|
+
|
|
76
|
+
const response = await fetch('/api/auth/login', {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: { 'Content-Type': 'application/json' },
|
|
79
|
+
body: JSON.stringify({ idToken }),
|
|
80
|
+
})
|
|
81
|
+
const resBody = (await response.json()) as unknown as APIResponse<string>
|
|
82
|
+
|
|
83
|
+
if (response.ok && resBody.success) {
|
|
84
|
+
return { success: true, user: userCreds.user }
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
return { success: false, user: null }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('Error signing in with Google', error)
|
|
92
|
+
return { success: false, user: null }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const isAuthUserNotFound = (e: any) => (
|
|
97
|
+
typeof e === 'object' &&
|
|
98
|
+
e !== null &&
|
|
99
|
+
e.hasOwnProperty('code') &&
|
|
100
|
+
e.code === 'auth/user-not-found'
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
export async function signupWithEmailAndPassword(
|
|
104
|
+
email: string,
|
|
105
|
+
password: string
|
|
106
|
+
): Promise<{ success: boolean, user?: User, message?: string }> {
|
|
107
|
+
if (!auth) {
|
|
108
|
+
return { success: false, message: 'Firebase auth not configured' }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let user: User | undefined = undefined
|
|
112
|
+
try {
|
|
113
|
+
const userCredential = await createUserWithEmailAndPassword(auth, email, password)
|
|
114
|
+
user = userCredential.user
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof FirebaseError) {
|
|
118
|
+
console.error(error.code)
|
|
119
|
+
return {success: false, message: error.code as string}
|
|
120
|
+
}
|
|
121
|
+
return {success: false, message: error as string}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const idToken = await user.getIdToken()
|
|
126
|
+
|
|
127
|
+
const response = await fetch('/api/auth/login', {
|
|
128
|
+
method: 'POST',
|
|
129
|
+
headers: { 'Content-Type': 'application/json' },
|
|
130
|
+
body: JSON.stringify({ idToken }),
|
|
131
|
+
})
|
|
132
|
+
const resBody = (await response.json()) as unknown as APIResponse<string>
|
|
133
|
+
|
|
134
|
+
if (response.ok && resBody.success) {
|
|
135
|
+
return { success: true, user }
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return { success: false }
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
console.error('Error signing in with Firebase auth', error)
|
|
143
|
+
return { success: false }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function loginWithEmailAndPassword(
|
|
148
|
+
email: string,
|
|
149
|
+
password: string
|
|
150
|
+
): Promise<{ success: boolean, user?: User, message?: string }> {
|
|
151
|
+
if (!auth) {
|
|
152
|
+
return { success: false, message: 'Firebase auth not configured' }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let user: User | undefined = undefined
|
|
156
|
+
try {
|
|
157
|
+
const userCredential = await signInWithEmailAndPassword(auth, email, password)
|
|
158
|
+
user = userCredential.user
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error instanceof FirebaseError) {
|
|
161
|
+
console.error(error.code)
|
|
162
|
+
return {success: false, message: error.code as string}
|
|
163
|
+
}
|
|
164
|
+
return {success: false, message: error as string}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const idToken = await user.getIdToken()
|
|
169
|
+
|
|
170
|
+
const response = await fetch('/api/auth/login', {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
headers: { 'Content-Type': 'application/json' },
|
|
173
|
+
body: JSON.stringify({ idToken }),
|
|
174
|
+
})
|
|
175
|
+
const resBody = (await response.json()) as unknown as APIResponse<string>
|
|
176
|
+
|
|
177
|
+
if (response.ok && resBody.success) {
|
|
178
|
+
return { success: true, user, message: "Login Successfully!" }
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return { success: false , message: "Login API Failed"}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.error('Error signing in with Firebase auth', error)
|
|
186
|
+
return { success: false, message: "Error signing in with Firebase auth" }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function loginWithCustomToken(
|
|
191
|
+
token: string,
|
|
192
|
+
): Promise<{ success: boolean, user?: User }> {
|
|
193
|
+
if (!auth) {
|
|
194
|
+
return { success: false }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let user: User | undefined = undefined
|
|
198
|
+
const userCredential = await signInWithCustomToken(auth, token)
|
|
199
|
+
user = userCredential.user
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const idToken = await user.getIdToken()
|
|
203
|
+
|
|
204
|
+
const response = await fetch('/api/auth/login', {
|
|
205
|
+
method: 'POST',
|
|
206
|
+
headers: { 'Content-Type': 'application/json' },
|
|
207
|
+
body: JSON.stringify({ idToken }),
|
|
208
|
+
})
|
|
209
|
+
const resBody = (await response.json()) as unknown as APIResponse<string>
|
|
210
|
+
|
|
211
|
+
if (response.ok && resBody.success) {
|
|
212
|
+
return { success: true, user }
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
return { success: false }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.error('Error signing in with Firebase auth', error)
|
|
220
|
+
return { success: false }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export async function logoutBackend(): Promise<{ success: boolean }> {
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const response = await fetch('/api/auth/logout', { headers: { 'Content-Type': 'application/json' } })
|
|
228
|
+
const resBody = (await response.json()) as unknown as APIResponse<string>
|
|
229
|
+
if (response.ok && resBody.success) {
|
|
230
|
+
return { success: true }
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
return { success: false }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
catch (error) {
|
|
238
|
+
console.error('Error logging on on server with Firebase', error)
|
|
239
|
+
return { success: false }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { makeAutoObservable, makeObservable, computed } from 'mobx'
|
|
2
|
+
|
|
3
|
+
import type AuthService from '../auth-service'
|
|
4
|
+
import type { AuthServiceConf, LibreAppsUserInfo, LibreAppsUserInfoValue } from '../../types'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
auth as fbAuth,
|
|
8
|
+
signupWithEmailAndPassword,
|
|
9
|
+
loginWithCustomToken,
|
|
10
|
+
loginWithEmailAndPassword,
|
|
11
|
+
loginWithProvider,
|
|
12
|
+
logoutBackend
|
|
13
|
+
} from './firebase-support'
|
|
14
|
+
import { associateWalletAddressWithAccount, getAssociatedWalletAddress } from './wallet-support'
|
|
15
|
+
|
|
16
|
+
class LibreAppsUserInfoStore implements LibreAppsUserInfo {
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
makeAutoObservable(this)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_email: string = ''
|
|
23
|
+
_displayName: string | null = null
|
|
24
|
+
_walletAddress: string | null = null
|
|
25
|
+
|
|
26
|
+
get email(): string { return this._email}
|
|
27
|
+
get displayName(): string | null { return this._displayName}
|
|
28
|
+
get walletAddress(): string | null { return this._walletAddress}
|
|
29
|
+
|
|
30
|
+
clear():void {
|
|
31
|
+
this._email = ''
|
|
32
|
+
this._displayName = null
|
|
33
|
+
this._walletAddress = null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
set(v: LibreAppsUserInfoValue):void {
|
|
37
|
+
this._email = v.email
|
|
38
|
+
this._displayName = v.displayName
|
|
39
|
+
this._walletAddress = v.walletAddress
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get isValid(): boolean {
|
|
43
|
+
return (this._email.length > 0)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AuthServiceImpl implements AuthService {
|
|
50
|
+
|
|
51
|
+
private _hzUser = new LibreAppsUserInfoStore()
|
|
52
|
+
|
|
53
|
+
constructor(conf: AuthServiceConf, user: LibreAppsUserInfoValue | null) {
|
|
54
|
+
|
|
55
|
+
makeObservable(this, {
|
|
56
|
+
loggedIn: computed,
|
|
57
|
+
user: computed
|
|
58
|
+
})
|
|
59
|
+
// ignore conf for now
|
|
60
|
+
if (user) {
|
|
61
|
+
this._hzUser.set(user)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get user(): LibreAppsUserInfo | null {
|
|
66
|
+
return this._hzUser.isValid ? this._hzUser : null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get loggedIn(): boolean {
|
|
70
|
+
return (
|
|
71
|
+
/*!!fbAuth.currentUser &&*/ this._hzUser.isValid
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
signupEmailAndPassword = async (
|
|
76
|
+
email: string,
|
|
77
|
+
password: string
|
|
78
|
+
): Promise<{success: boolean, userInfo: LibreAppsUserInfo | null, message?: string}> => {
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
this._hzUser.clear()
|
|
82
|
+
const res = await signupWithEmailAndPassword(email, password)
|
|
83
|
+
if (res.success && res.user) {
|
|
84
|
+
const walletAddress = res.user.email ? await getAssociatedWalletAddress(res.user.email) : undefined
|
|
85
|
+
this._hzUser.set({
|
|
86
|
+
email: res.user.email ?? '',
|
|
87
|
+
displayName : res.user.displayName ?? null,
|
|
88
|
+
walletAddress : walletAddress?.result ?? null
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
userInfo: this._hzUser,
|
|
94
|
+
message: res.message
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
userInfo: null,
|
|
100
|
+
message: res.message
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
console.error('Error signing in with Firebase auth', e)
|
|
105
|
+
return {success: false, userInfo: null, message: 'Error signing in with Firebase auth'}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
loginEmailAndPassword = async (
|
|
110
|
+
email: string,
|
|
111
|
+
password: string
|
|
112
|
+
): Promise<{success: boolean, userInfo: LibreAppsUserInfo | null, message?: string}> => {
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
this._hzUser.clear()
|
|
116
|
+
const res = await loginWithEmailAndPassword(email, password)
|
|
117
|
+
if (res.success && res.user) {
|
|
118
|
+
const walletAddress = res.user.email ? await getAssociatedWalletAddress(res.user.email) : undefined
|
|
119
|
+
this._hzUser.set({
|
|
120
|
+
email: res.user.email ?? '',
|
|
121
|
+
displayName : res.user.displayName ?? null,
|
|
122
|
+
walletAddress : walletAddress?.result ?? null
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
userInfo: this._hzUser,
|
|
128
|
+
message: res.message
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
userInfo: null,
|
|
134
|
+
message: res.message
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
console.error('Error signing in with Firebase auth', e)
|
|
139
|
+
return {success: false, userInfo: null, message: 'Error signing in with Firebase auth'}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
loginWithProvider = async (
|
|
144
|
+
provider: 'google' | 'facebook' | 'github'
|
|
145
|
+
): Promise<{success: boolean, userInfo: LibreAppsUserInfo | null}> => {
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
this._hzUser.clear()
|
|
149
|
+
const res = await loginWithProvider(provider)
|
|
150
|
+
if (res.success && res.user) {
|
|
151
|
+
const walletAddress = res.user.email ? await getAssociatedWalletAddress(res.user.email) : undefined
|
|
152
|
+
this._hzUser.set({
|
|
153
|
+
email: res.user.email ?? '',
|
|
154
|
+
displayName : res.user.displayName ?? null,
|
|
155
|
+
walletAddress : walletAddress?.result ?? null
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
userInfo: this._hzUser
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
userInfo: null
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
console.error('Error signing in with Firebase auth', e)
|
|
170
|
+
return {success: false, userInfo: null}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
loginWithCustomToken = async (
|
|
175
|
+
token: string
|
|
176
|
+
): Promise<{success: boolean, userInfo: LibreAppsUserInfo | null}> => {
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
this._hzUser.clear()
|
|
180
|
+
const res = await loginWithCustomToken(token)
|
|
181
|
+
if (res.success && res.user) {
|
|
182
|
+
const walletAddress = res.user.email ? await getAssociatedWalletAddress(res.user.email) : undefined
|
|
183
|
+
this._hzUser.set({
|
|
184
|
+
email: res.user.email ?? '',
|
|
185
|
+
displayName : res.user.displayName ?? null,
|
|
186
|
+
walletAddress : walletAddress?.result ?? null
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
userInfo: this._hzUser
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
success: false,
|
|
196
|
+
userInfo: null
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
console.error('Error signing in with Firebase auth', e)
|
|
201
|
+
return {success: false, userInfo: null}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
associateWallet = async (): Promise<void> => {
|
|
206
|
+
if (this._hzUser.isValid) {
|
|
207
|
+
const res = await associateWalletAddressWithAccount(this._hzUser.email)
|
|
208
|
+
if (!res.error) {
|
|
209
|
+
//runInAction(() => {
|
|
210
|
+
this._hzUser._walletAddress = res.result ?? null
|
|
211
|
+
//})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
logout = async (): Promise<{ success: boolean }> => {
|
|
217
|
+
if (fbAuth) {
|
|
218
|
+
await fbAuth.signOut()
|
|
219
|
+
}
|
|
220
|
+
this._hzUser.clear()
|
|
221
|
+
return await logoutBackend()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
setServerSideUser = (user: LibreAppsUserInfoValue | null) => {
|
|
225
|
+
if (user) {
|
|
226
|
+
this._hzUser.set(user)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export default AuthServiceImpl
|