UNPKG

4.41 kBJavaScriptView Raw
1// A simple ghauth inspired library for getting a personal access token
2const Octokit = require('@octokit/rest')
3const inquirer = require('inquirer')
4const querystring = require('querystring')
5const get = require('lodash.get')
6const open = require('open')
7const http = require('http')
8const getPort = require('get-port')
9
10module.exports = getGitHubToken
11
12async function getGitHubToken(opts) {
13 console.log('')
14
15 opts = Object.assign(
16 {
17 userAgent: 'Netlify-cli-octokit',
18 note: 'Netlify-cli-gh-auth',
19 scopes: []
20 },
21 opts
22 )
23
24 async function promptForOTP() {
25 const { otp } = await inquirer.prompt([
26 {
27 type: 'input',
28 name: 'otp',
29 message: 'Your GitHub OTP/2FA Code:',
30 filter: input => input.trim()
31 }
32 ])
33 return otp
34 }
35
36 const authChoiceNetlify = 'Authorize with GitHub through app.netlify.com'
37 const authChoiceManual = 'Enter your GitHub credentials manually'
38 const authChoices = [authChoiceNetlify, authChoiceManual]
39
40 const { initChoice } = await inquirer.prompt([
41 {
42 type: 'list',
43 name: 'initChoice',
44 message:
45 'Netlify CLI needs access to your GitHub account to configure Webhooks and Deploy Keys. ' +
46 'What would you like to do?',
47 choices: authChoices
48 }
49 ])
50
51 if (initChoice === authChoiceNetlify) {
52 const port = await getPort({ port: 3000 })
53 let deferredResolve
54 let deferredReject
55 const deferredPromise = new Promise(function(resolve, reject) {
56 deferredResolve = resolve
57 deferredReject = reject
58 })
59
60 const server = http.createServer(function(req, res) {
61 const parameters = querystring.parse(req.url.slice(req.url.indexOf('?') + 1))
62 if (parameters.token) {
63 deferredResolve(parameters)
64 res.end(
65 "<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>" +
66 "<body><div class=card><h3>Logged In</h3><p>You're now logged into Netlify CLI with your " +
67 parameters.provider +
68 ' credentials. Please close this window.</p></div>'
69 )
70 server.close()
71 return
72 }
73 res.end('BAD PARAMETERS')
74 server.close()
75 deferredReject(new Error('Got invalid parameters for CLI login'))
76 })
77
78 await new Promise(function(resolve, reject) {
79 server.on('error', reject)
80 server.listen(port, resolve)
81 })
82
83 const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com'
84 const url =
85 webUI +
86 '/cli?' +
87 querystring.encode({
88 host: 'http://localhost:' + port,
89 provider: 'github'
90 })
91
92 try {
93 await open(url)
94 } catch (err) {
95 console.log(
96 'Netlify CLI could not open the browser for you.' + ' Please visit this URL in a browser on this device: ' + url
97 )
98 }
99
100 return await deferredPromise
101 } else {
102 const { username, password } = await inquirer.prompt([
103 {
104 type: 'input',
105 name: 'username',
106 message: 'Your GitHub username:',
107 filter: input => input.trim()
108 },
109 {
110 type: 'password',
111 name: 'password',
112 message: 'Your GitHub password:',
113 mask: '*',
114 filter: input => input.trim()
115 }
116 ])
117
118 // configure basic auth
119 const octokit = new Octokit({
120 auth: {
121 username,
122 password,
123 async on2fa() {
124 return promptForOTP()
125 }
126 }
127 })
128
129 let response = await octokit.oauthAuthorizations.createAuthorization({
130 note: opts.note + ' (' + new Date().toJSON() + ')',
131 note_url: 'https://cli.netlify.com/',
132 scopes: opts.scopes,
133 headers: {
134 'User-Agent': opts.userAgent
135 }
136 })
137
138 if (get(response, 'data.token')) {
139 return { user: username, token: get(response, 'data.token') }
140 } else {
141 const error = new Error('Github authentication failed')
142 error.response = response
143 throw error
144 }
145 }
146}