1 | const { Command } = require('@oclif/command')
|
2 | const API = require('netlify')
|
3 | const merge = require('lodash.merge')
|
4 | const { format, inspect } = require('util')
|
5 | const { URL } = require('url')
|
6 | const { track, identify } = require('./telemetry')
|
7 | const openBrowser = require('./open-browser')
|
8 | const StateConfig = require('./state-config')
|
9 | const globalConfig = require('./global-config')
|
10 | const findRoot = require('./find-root')
|
11 | const chalkInstance = require('./chalk')
|
12 | const resolveConfig = require('@netlify/config')
|
13 | const getConfigPath = require('@netlify/config').getConfigPath
|
14 |
|
15 | const argv = require('minimist')(process.argv.slice(2))
|
16 | const { NETLIFY_AUTH_TOKEN, NETLIFY_API_URL } = process.env
|
17 |
|
18 |
|
19 |
|
20 | const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750'
|
21 |
|
22 | class BaseCommand extends Command {
|
23 | constructor(...args) {
|
24 | super(...args)
|
25 | }
|
26 |
|
27 | async init(_projectRoot) {
|
28 | const cwd = argv.cwd || process.cwd()
|
29 | const projectRoot = findRoot(_projectRoot || cwd)
|
30 |
|
31 | const authViaFlag = getAuthArg(argv)
|
32 |
|
33 | const [token] = this.getConfigToken(authViaFlag)
|
34 |
|
35 |
|
36 | const configPath = await getConfigPath(argv.config, cwd)
|
37 | const config = await resolveConfig(configPath, {
|
38 | cwd: cwd,
|
39 | context: argv.context
|
40 | })
|
41 |
|
42 |
|
43 | const state = new StateConfig(projectRoot)
|
44 |
|
45 | const apiOpts = {}
|
46 | if (NETLIFY_API_URL) {
|
47 | const apiUrl = new URL(NETLIFY_API_URL)
|
48 | apiOpts.scheme = apiUrl.protocol.substring(0, apiUrl.protocol.length - 1)
|
49 | apiOpts.host = apiUrl.host
|
50 | apiOpts.pathPrefix = NETLIFY_API_URL === `${apiUrl.protocol}//${apiUrl.host}` ? '/api/v1' : apiUrl.pathname
|
51 | }
|
52 |
|
53 | this.netlify = {
|
54 |
|
55 | api: new API(token || '', apiOpts),
|
56 |
|
57 | site: {
|
58 | root: projectRoot,
|
59 | configPath: configPath,
|
60 | get id() {
|
61 | return state.get('siteId')
|
62 | },
|
63 | set id(id) {
|
64 | state.set('siteId', id)
|
65 | }
|
66 | },
|
67 |
|
68 | config: config,
|
69 |
|
70 | globalConfig: globalConfig,
|
71 |
|
72 | state: state
|
73 | }
|
74 | }
|
75 |
|
76 | async isLoggedIn() {
|
77 | try {
|
78 | await this.netlify.api.getCurrentUser()
|
79 | return true
|
80 | } catch (_) {
|
81 | return false
|
82 | }
|
83 | }
|
84 |
|
85 | logJson(message = '', ...args) {
|
86 |
|
87 | if (!argv.json) {
|
88 | return
|
89 | }
|
90 | process.stdout.write(JSON.stringify(message, null, 2))
|
91 | }
|
92 |
|
93 | log(message = '', ...args) {
|
94 |
|
95 | if (argv.silent || argv.json) {
|
96 | return
|
97 | }
|
98 | message = typeof message === 'string' ? message : inspect(message)
|
99 | process.stdout.write(format(message, ...args) + '\n')
|
100 | }
|
101 |
|
102 |
|
103 | parse(opts, argv = this.argv) {
|
104 |
|
105 | if (!opts.flags) {
|
106 | opts.flags = {}
|
107 | }
|
108 |
|
109 | const globalFlags = {}
|
110 | if (!opts.flags.silent) {
|
111 | globalFlags['silent'] = {
|
112 | parse: (b, _) => b,
|
113 | description: 'Silence CLI output',
|
114 | allowNo: false,
|
115 | type: 'boolean'
|
116 | }
|
117 | }
|
118 | if (!opts.flags.json) {
|
119 | globalFlags['json'] = {
|
120 | parse: (b, _) => b,
|
121 | description: 'Output return values as JSON',
|
122 | allowNo: false,
|
123 | type: 'boolean'
|
124 | }
|
125 | }
|
126 | if (!opts.flags.auth) {
|
127 | globalFlags['auth'] = {
|
128 | parse: (b, _) => b,
|
129 | description: 'Netlify auth token',
|
130 | input: [],
|
131 | multiple: false,
|
132 | type: 'option'
|
133 | }
|
134 | }
|
135 |
|
136 |
|
137 | opts.flags = Object.assign({}, opts.flags, globalFlags)
|
138 |
|
139 | return require('@oclif/parser').parse(
|
140 | argv,
|
141 | Object.assign(
|
142 | {},
|
143 | {
|
144 | context: this
|
145 | },
|
146 | opts
|
147 | )
|
148 | )
|
149 | }
|
150 |
|
151 | get chalk() {
|
152 |
|
153 | return chalkInstance(argv.json)
|
154 | }
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 | getConfigToken(tokenFromFlag) {
|
161 |
|
162 | if (tokenFromFlag) {
|
163 | return [tokenFromFlag, 'flag']
|
164 | }
|
165 |
|
166 | if (NETLIFY_AUTH_TOKEN && NETLIFY_AUTH_TOKEN !== 'null') {
|
167 | return [NETLIFY_AUTH_TOKEN, 'env']
|
168 | }
|
169 |
|
170 | const userId = globalConfig.get('userId')
|
171 | const tokenFromConfig = globalConfig.get(`users.${userId}.auth.token`)
|
172 | if (tokenFromConfig) {
|
173 | return [tokenFromConfig, 'config']
|
174 | }
|
175 | return [null, 'not found']
|
176 | }
|
177 |
|
178 | async authenticate(tokenFromFlag) {
|
179 | const [token] = this.getConfigToken(tokenFromFlag)
|
180 | if (!token) {
|
181 | return this.expensivelyAuthenticate()
|
182 | } else {
|
183 | return token
|
184 | }
|
185 | }
|
186 |
|
187 | async expensivelyAuthenticate() {
|
188 | const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com'
|
189 | this.log(`Logging into your Netlify account...`)
|
190 |
|
191 |
|
192 | const ticket = await this.netlify.api.createTicket({
|
193 | clientId: CLIENT_ID
|
194 | })
|
195 |
|
196 |
|
197 | const authLink = `${webUI}/authorize?response_type=ticket&ticket=${ticket.id}`
|
198 |
|
199 | this.log(`Opening ${authLink}`)
|
200 | await openBrowser(authLink)
|
201 |
|
202 | const accessToken = await this.netlify.api.getAccessToken(ticket)
|
203 |
|
204 | if (!accessToken) {
|
205 | this.error('Could not retrieve access token')
|
206 | }
|
207 |
|
208 | const user = await this.netlify.api.getCurrentUser()
|
209 | const userID = user.id
|
210 |
|
211 | const userData = merge(this.netlify.globalConfig.get(`users.${userID}`), {
|
212 | id: userID,
|
213 | name: user.full_name,
|
214 | email: user.email,
|
215 | auth: {
|
216 | token: accessToken,
|
217 | github: {
|
218 | user: undefined,
|
219 | token: undefined
|
220 | }
|
221 | }
|
222 | })
|
223 |
|
224 | this.netlify.globalConfig.set('userId', userID)
|
225 |
|
226 | this.netlify.globalConfig.set(`users.${userID}`, userData)
|
227 |
|
228 | const email = user.email
|
229 | await identify({
|
230 | name: user.full_name,
|
231 | email: email
|
232 | }).then(() => {
|
233 | return track('user_login', {
|
234 | email: email
|
235 | })
|
236 | })
|
237 |
|
238 |
|
239 | this.log()
|
240 | this.log(`${this.chalk.greenBright('You are now logged into your Netlify account!')}`)
|
241 | this.log()
|
242 | this.log(`Run ${this.chalk.cyanBright('netlify status')} for account details`)
|
243 | this.log()
|
244 | this.log(`To see all available commands run: ${this.chalk.cyanBright('netlify help')}`)
|
245 | this.log()
|
246 | return accessToken
|
247 | }
|
248 | }
|
249 |
|
250 | function getAuthArg(cliArgs) {
|
251 |
|
252 | if (cliArgs && cliArgs._ && cliArgs._[0] === 'deploy') {
|
253 | return cliArgs.auth || cliArgs.a
|
254 | }
|
255 | return cliArgs.auth
|
256 | }
|
257 |
|
258 | module.exports = BaseCommand
|