-
Notifications
You must be signed in to change notification settings - Fork 22
/
index.ts
111 lines (94 loc) · 3.98 KB
/
index.ts
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
import axios from 'axios'
import { createHash } from 'crypto'
import isWsl from 'is-wsl'
import jwt from 'jsonwebtoken'
import opn from 'opn'
import { join } from 'path'
import { logger } from '../../../../api'
import { VTEXID } from '../../../../api/clients/IOClients/external/VTEXID'
import { storeUrl } from '../../../../api/storeUrl'
import { ColorifyConstants } from '../../../constants/Colors'
import { formatHyperlink } from '../../../utils/Messages'
import { randomCryptoString } from '../../../utils/randomCryptoString'
import { spawnUnblockingChildProcess } from '../../../utils/spawnUnblockingChildProcess'
import { AuthProviderBase } from '../AuthProviderBase'
import { LoginServer } from './LoginServer'
export class OAuthAuthenticator extends AuthProviderBase {
public static readonly AUTH_TYPE = 'oauth'
private static readonly SECRET_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
private static ADMIN_LOGIN_URL_PATH = '/_v/segment/admin-login/v1/login'
private static FALLBACK_AUTH_SERVER_LOGIN_URL_PATH = '/_v/private/auth-server/v1/login'
public async login(account: string) {
const secret = randomCryptoString(128, OAuthAuthenticator.SECRET_ALPHABET)
const secretHash = this.hashSecret(secret)
const vtexId = VTEXID.createClient({ account })
const loginServer = await LoginServer.create({
account,
secret,
})
try {
const loginState = await vtexId.startToolbeltLogin({
account,
secretHash,
loopbackUrl: loginServer.loginCallbackUrl,
})
loginServer.setLoginState(loginState)
const url = await this.loginUrl(account, loginState)
opn(url, { wait: false })
if(isWsl) {
logger.warn("We noticed you're using WSL, in which case you may face login issues depending on you WSL version.")
logger.warn(`If you do, make sure your Windows is up to date and try again${formatHyperlink('', "https://support.microsoft.com/en-us/help/4027667/windows-10-update")}.`)
logger.warn(`In case login errors persist after updating please create an issue on ${ColorifyConstants.URL_INTERACTIVE("https://github.com/vtex/toolbelt/issues")}. We'll promptly help you finding a solution.`)
}
const token = await loginServer.token
const decodedToken = jwt.decode(token)
const login: string = decodedToken.sub
this.closeChromeTabIfMac(loginServer.loginCallbackUrl)
return { login, token }
} finally {
loginServer.close()
}
}
private hashSecret(secret: string) {
return createHash('sha256')
.update(secret)
.digest('base64')
}
private async loginUrl(account: string, loginState: string) {
const hasAdminLogin = await this.hasAdminLoginInstalled(account)
const returnUrl = `/api/vtexid/toolbelt/callback?state=${encodeURIComponent(loginState)}`
let loginPathPrefix: string
if (!hasAdminLogin) {
// If for some reason vtex.admin-login is not installed in the account, fallback to use auth-server login url
loginPathPrefix = storeUrl({
account,
addWorkspace: false,
path: OAuthAuthenticator.FALLBACK_AUTH_SERVER_LOGIN_URL_PATH,
})
} else {
loginPathPrefix = storeUrl({ account, addWorkspace: false, path: OAuthAuthenticator.ADMIN_LOGIN_URL_PATH })
}
return `${loginPathPrefix}?returnUrl=${encodeURIComponent(returnUrl)}`
}
private async hasAdminLoginInstalled(account: string) {
try {
const { data } = await axios.get<string>(
storeUrl({ account, addWorkspace: false, path: '/_v/segment/admin-login/v1/login' })
)
return data.includes('vtex.admin-login')
} catch (err) {
if (err.response?.status === 404) {
return false
}
throw err
}
}
private closeChromeTabIfMac(loginCallbackUrl: string) {
if (process.platform === 'darwin') {
spawnUnblockingChildProcess('osascript', [
join(__dirname, '../../../../scripts/closeChrome.scpt'),
loginCallbackUrl,
])
}
}
}