forked from netlify/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgh-auth.js
More file actions
157 lines (135 loc) · 4.72 KB
/
Copy pathgh-auth.js
File metadata and controls
157 lines (135 loc) · 4.72 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// A simple ghauth inspired library for getting a personal access token
const http = require('http')
const os = require('os')
const process = require('process')
const querystring = require('querystring')
const { Octokit } = require('@octokit/rest')
const dotProp = require('dot-prop')
const getPort = require('get-port')
const inquirer = require('inquirer')
const { version } = require('../../package.json')
const { createDeferred } = require('./deferred')
const openBrowser = require('./open-browser')
const SERVER_PORT = 3000
const USER_AGENT = `Netlify CLI ${version}`
const promptForOTP = async function () {
const { otp } = await inquirer.prompt([
{
type: 'input',
name: 'otp',
message: 'Your GitHub OTP/2FA Code:',
filter: (input) => input.trim(),
},
])
return otp
}
const promptForAuthMethod = async () => {
const authChoiceNetlify = 'Authorize with GitHub through app.netlify.com'
const authChoiceManual = 'Enter your GitHub credentials manually'
const authChoices = [authChoiceNetlify, authChoiceManual]
const { authMethod } = await inquirer.prompt([
{
type: 'list',
name: 'authMethod',
message:
'Netlify CLI needs access to your GitHub account to configure Webhooks and Deploy Keys. ' +
'What would you like to do?',
choices: authChoices,
},
])
return authMethod === authChoiceNetlify
}
const authWithNetlify = async ({ log }) => {
const port = await getPort({ port: SERVER_PORT })
const { promise: deferredPromise, reject: deferredReject, resolve: deferredResolve } = createDeferred()
const server = http.createServer(function onRequest(req, res) {
const parameters = querystring.parse(req.url.slice(req.url.indexOf('?') + 1))
if (parameters.token) {
deferredResolve(parameters)
res.end(
`${
"<html><head><script>if(history.replaceState){history.replaceState({},'','/')}</script><style>html{font-family:sans-serif;background:#0e1e25}body{overflow:hidden;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;width:100vw;}h3{margin:0}.card{position:relative;display:flex;flex-direction:column;width:75%;max-width:364px;padding:24px;background:white;color:rgb(14,30,37);border-radius:8px;box-shadow:0 2px 4px 0 rgba(14,30,37,.16);}</style></head>" +
"<body><div class=card><h3>Logged In</h3><p>You're now logged into Netlify CLI with your "
}${parameters.provider} credentials. Please close this window.</p></div>`,
)
server.close()
return
}
res.end('BAD PARAMETERS')
server.close()
deferredReject(new Error('Got invalid parameters for CLI login'))
})
await new Promise(function waitForListening(resolve, reject) {
server.on('error', reject)
server.listen(port, resolve)
})
const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com'
const url = `${webUI}/cli?${querystring.encode({
host: `http://localhost:${port}`,
provider: 'github',
})}`
await openBrowser({ url, log })
return deferredPromise
}
const getUsernameAndPassword = async () => {
const { username, password } = await inquirer.prompt([
{
type: 'input',
name: 'username',
message: 'Your GitHub username:',
filter: (input) => input.trim(),
},
{
type: 'password',
name: 'password',
message: 'Your GitHub password:',
mask: '*',
filter: (input) => input.trim(),
},
])
return { username, password }
}
const getGitHubClient = ({ username, password }) => {
// configure basic auth
const octokit = new Octokit({
auth: {
username,
password,
on2fa() {
return promptForOTP()
},
},
})
return octokit
}
const createAuthorization = async ({ octokit }) => {
const response = await octokit.oauthAuthorizations.createAuthorization({
note: `Netlify CLI ${os.userInfo().username}@${os.hostname()} (${new Date().toJSON()})`,
note_url: 'https://cli.netlify.com/',
scopes: ['admin:org', 'admin:public_key', 'repo', 'user'],
headers: {
'User-Agent': USER_AGENT,
},
})
return response
}
const authManually = async () => {
const { username, password } = await getUsernameAndPassword()
const octokit = getGitHubClient({ username, password })
const response = await createAuthorization(octokit)
const token = dotProp.get(response, 'data.token')
if (token) {
return { user: username, token }
}
const error = new Error('Github authentication failed')
error.response = response
throw error
}
module.exports = async function getGitHubToken({ log }) {
log('')
const withNetlify = await promptForAuthMethod()
if (withNetlify) {
return await authWithNetlify({ log })
}
await authManually()
}