-
Notifications
You must be signed in to change notification settings - Fork 360
Expand file tree
/
Copy pathauth-sync.ts
More file actions
140 lines (126 loc) · 4.33 KB
/
auth-sync.ts
File metadata and controls
140 lines (126 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import {
unpackMessage,
validMessage,
packMessage,
ExtMessage,
validGeneratedLoginToken,
logUnpackedMessage,
logPackedMessage,
} from '@worldbrain/memex-common/lib/authentication/auth-sync'
import { AuthService } from '@worldbrain/memex-common/lib/authentication/types'
function validSender(sender: any, expectedOrigins: string[]) {
if (!(typeof sender === 'object' && typeof sender.origin === 'string')) {
return false
}
return expectedOrigins.includes(sender.origin)
}
function getMessage(
message: any,
sender: any,
expectedOrigins: string[],
): null | ReturnType<typeof unpackMessage> {
if (!validSender(sender, expectedOrigins) || !validMessage(message)) {
return null
}
return unpackMessage(message)
}
const enableMessageLogging = false
function addListener(
listener: (
sendResponse: (obj: ReturnType<typeof packMessage>) => void,
messageObj: ReturnType<typeof unpackMessage>,
) => void,
expectedOrigins: string[],
) {
//@ts-ignore next-line
const base = chrome || browser
if (!base) {
return
}
//@ts-ignore next-line
base.runtime.onMessageExternal.addListener(
(message, sender, runtimeSendResponse) => {
const messageObj = getMessage(message, sender, expectedOrigins)
if (!messageObj) {
return
}
logUnpackedMessage(messageObj, 'Recieved', enableMessageLogging)
const sendResponse = (msg) => {
logPackedMessage(msg, 'Sending', enableMessageLogging)
runtimeSendResponse(msg)
}
return listener(sendResponse, messageObj)
},
)
}
async function sendTokenToAppHandler(
authService: AuthService,
sendResponse: (obj: ReturnType<typeof packMessage>) => void,
messageObj: ReturnType<typeof unpackMessage>,
) {
console.log('Trying to send token to app.')
if (messageObj.message !== ExtMessage.TOKEN_REQUEST) {
sendResponse(packMessage(ExtMessage.LOGGED_IN))
return
}
await authService.generateLoginToken().then((tokenObj) => {
const loginToken = tokenObj.token
if (!validGeneratedLoginToken(loginToken)) {
return
}
sendResponse(packMessage(ExtMessage.TOKEN, loginToken))
})
}
async function loginWithAppTokenHandler(
authService: AuthService,
sendResponse: (obj: ReturnType<typeof packMessage>) => void,
messageObj: ReturnType<typeof unpackMessage>,
) {
console.log('Trying to get token from app.')
if (messageObj.message === ExtMessage.TOKEN) {
if (messageObj.payload) {
await authService.loginWithToken(messageObj.payload)
}
} else {
sendResponse(packMessage(ExtMessage.TOKEN_REQUEST))
}
}
export async function listenToWebAppMessage(authService: AuthService) {
const expectedOrigins =
process.env.NODE_ENV === 'production'
? ['https://memex.social']
: ['http://localhost:3000', 'https://staging.memex.social']
await authService.waitForAuthReady()
let reactingToMessage = false
addListener((sendResponse, messageObj) => {
// JS is mostly event-loop concurrent: https://stackoverflow.com/a/5347062
// So we have a simple lock here to prevent multiple tabs of the app contacting the extension, this works so-so
// This will not prevent multiple instances of the service worker to react
if (reactingToMessage) {
return false
}
reactingToMessage = true
// Can not use a promise here, otherwise the listener will never resolve
authService
.getCurrentUser()
.then((val) => {
const isLoggedIn = !!val
if (isLoggedIn) {
return sendTokenToAppHandler(
authService,
sendResponse,
messageObj,
)
} else {
return loginWithAppTokenHandler(
authService,
sendResponse,
messageObj,
)
}
})
.then(() => (reactingToMessage = false))
// Indicates that we want to send an async response
return true
}, expectedOrigins)
}