Browse Source

Google Cloud Platform support is working again

master
Leo Lamprecht 7 years ago
parent
commit
665e36eddf
  1. 44
      src/now.js
  2. 349
      src/providers/gcp/login.js

44
src/now.js

@ -28,7 +28,7 @@ const NOW_AUTH_CONFIG_PATH = configFiles.getAuthConfigFilePath()
const GLOBAL_COMMANDS = new Set(['help']) const GLOBAL_COMMANDS = new Set(['help'])
const main = async (argv_): Promise<number> => { const main = async (argv_) => {
await checkForUpdates() await checkForUpdates()
const argv = mri(argv_, { const argv = mri(argv_, {
@ -64,7 +64,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
if (!nowDirExists) { if (!nowDirExists) {
@ -91,7 +91,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
let config let config
@ -107,7 +107,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
try { try {
@ -119,7 +119,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
} else { } else {
config = getDefaultCfg() config = getDefaultCfg()
@ -133,7 +133,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
} }
@ -149,7 +149,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
let authConfig = null let authConfig = null
@ -165,7 +165,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
try { try {
@ -178,7 +178,7 @@ const main = async (argv_): Promise<number> => {
'No `credentials` list found inside' 'No `credentials` list found inside'
) )
) )
return 1 return
} }
for (const [i, { provider }] of authConfig.credentials.entries()) { for (const [i, { provider }] of authConfig.credentials.entries()) {
@ -189,7 +189,7 @@ const main = async (argv_): Promise<number> => {
`Missing \`provider\` key in entry with index ${i}` `Missing \`provider\` key in entry with index ${i}`
) )
) )
return 1 return
} }
if (!(provider in providers)) { if (!(provider in providers)) {
@ -199,7 +199,7 @@ const main = async (argv_): Promise<number> => {
`Unknown provider "${provider}"` `Unknown provider "${provider}"`
) )
) )
return 1 return
} }
} }
} catch (err) { } catch (err) {
@ -210,7 +210,7 @@ const main = async (argv_): Promise<number> => {
)}": ` + err.message )}": ` + err.message
) )
) )
return 1 return
} }
} else { } else {
authConfig = getDefaultAuthCfg() authConfig = getDefaultAuthCfg()
@ -225,7 +225,7 @@ const main = async (argv_): Promise<number> => {
err.message err.message
) )
) )
return 1 return
} }
} }
@ -250,7 +250,7 @@ const main = async (argv_): Promise<number> => {
`An unexpected error occurred in config ${subcommand}: ${err.stack}` `An unexpected error occurred in config ${subcommand}: ${err.stack}`
) )
) )
return 1 return
} }
} }
@ -269,7 +269,7 @@ const main = async (argv_): Promise<number> => {
'Both a directory and a provider are known' 'Both a directory and a provider are known'
) )
) )
return 1 return
} }
suppliedProvider = targetOrSubcommand suppliedProvider = targetOrSubcommand
@ -299,12 +299,13 @@ const main = async (argv_): Promise<number> => {
`"${NOW_CONFIG_PATH}" is not a valid provider` `"${NOW_CONFIG_PATH}" is not a valid provider`
) )
) )
return 1 return
} }
} }
} }
const provider: Object = providers[suppliedProvider || defaultProvider] const providerName = suppliedProvider || defaultProvider
const provider: Object = providers[providerName]
let subcommand let subcommand
@ -324,7 +325,7 @@ const main = async (argv_): Promise<number> => {
'Both a directory and a subcommand are known' 'Both a directory and a subcommand are known'
) )
) )
return 1 return
} }
if (subcommandExists) { if (subcommandExists) {
@ -353,14 +354,17 @@ const main = async (argv_): Promise<number> => {
} }
try { try {
return provider[subcommand](ctx) await provider[subcommand](ctx)
} catch (err) { } catch (err) {
console.error( console.error(
error( error(
`An unexpected error occurred in provider ${subcommand}: ${err.stack}` `An unexpected error occurred in provider ${subcommand}: ${err.stack}`
) )
) )
return 1 }
if (providerName === 'gcp') {
process.exit()
} }
} }

349
src/providers/gcp/login.js

@ -57,220 +57,219 @@ const serverListen = ({ server, port }) => {
}) })
} }
function login(ctx) { const login = ctx => new Promise(async resolve => {
return new Promise(async resolve => { let credentialsIndex = ctx.authConfig.credentials.findIndex(
let credentialsIndex = ctx.authConfig.credentials.findIndex( cred => cred.provider === 'gcp'
cred => cred.provider === 'gcp' )
)
if (credentialsIndex !== -1) { if (credentialsIndex !== -1) {
// the user is already logged into gcp // the user is already logged into gcp
let yes let yes
try { try {
yes = await promptBool( yes = await promptBool(
info( info(
`You already have GCP credentials – this will replace them.`, `You already have GCP credentials – this will replace them.`,
` Do you want to continue?` ` Do you want to continue?`
)
) )
} catch (err) { )
// promptBool only `reject`s upon user abort } catch (err) {
// let's set it to false just to make it clear // promptBool only `reject`s upon user abort
yes = false // let's set it to false just to make it clear
} yes = false
}
if (!yes) { if (!yes) {
console.log(aborted('No changes made.')) console.log(aborted('No changes made.'))
resolve(0) return
}
} }
}
const ports = [...PORTS] const ports = [...PORTS]
const server = createServer(async function handleRequest(req, res) { const server = createServer(async function handleRequest(req, res) {
const { query: { error: _error, code } } = parseUrl(req.url, true) const { query: { error: _error, code } } = parseUrl(req.url, true)
if (!_error && !code) { if (!_error && !code) {
// the browser requesting the favicon etc // the browser requesting the favicon etc
res.end('') res.end('')
return return
} }
res.setHeader('content-type', 'text/html')
res.end(
`<meta charset="UTF-8">` +
`<h2>That's it – you can now return to your terminal!</h2>`
)
if (_error) { res.setHeader('content-type', 'text/html')
// the user didn't give us permission res.end(
console.log(aborted(`No changes made.`)) `<meta charset="UTF-8">` +
return resolve(1) `<h2>That's it – you can now return to your terminal!</h2>`
} )
if (code) { if (_error) {
// that's right after the user gave us permission // the user didn't give us permission
// let's exchange the authorization code for an access + refresh codes console.log(aborted(`No changes made.`))
return
}
const body = formUrlEncode({ if (code) {
code, // that's right after the user gave us permission
client_id: CLIENT_ID, // let's exchange the authorization code for an access + refresh codes
client_secret: CLIENT_SECRET,
redirect_uri: `http://${req.headers.host}`,
grant_type: GRANT_TYPE
})
const opts = { const body = formUrlEncode({
method: 'POST', code,
headers: { client_id: CLIENT_ID,
'content-type': 'application/x-www-form-urlencoded', client_secret: CLIENT_SECRET,
'content-length': body.length // just in case redirect_uri: `http://${req.headers.host}`,
}, grant_type: GRANT_TYPE
body: body })
}
let accessToken const opts = {
let expiresIn method: 'POST',
let refreshToken headers: {
let response 'content-type': 'application/x-www-form-urlencoded',
'content-length': body.length // just in case
},
body: body
}
try { let accessToken
response = await fetch(TOKEN_URL, opts) let expiresIn
if (response.status !== 200) { let refreshToken
debug( let response
`HTTP ${response.status} when trying to exchange the authorization code`,
await response.text()
)
console.log(
error(
`Got unexpected status code from Google: ${response.status}`
)
)
return resolve(1)
}
} catch (err) {
debug(
'unexpected error occurred while making the request to exchange the authorization code',
err.message
)
console.log(
error(
'Unexpected error occurred while authenthing with Google',
err.stack
)
)
return resolve(1)
}
try { try {
const json = await response.json() response = await fetch(TOKEN_URL, opts)
accessToken = json.access_token if (response.status !== 200) {
expiresIn = json.expires_in
refreshToken = json.refresh_token
} catch (err) {
debug( debug(
'unexpected error occurred while parsing the JSON from the exchange request', `HTTP ${response.status} when trying to exchange the authorization code`,
err.stack,
'got',
await response.text() await response.text()
) )
console.log( console.log(
error( error(
'Unexpected error occurred while parsing the JSON response from Google', `Got unexpected status code from Google: ${response.status}`
err.message
) )
) )
resolve(1) return
} }
} catch (err) {
const now = new Date() debug(
// `expires_in` is 3600 seconds 'unexpected error occurred while making the request to exchange the authorization code',
const expiresAt = now.setSeconds(now.getSeconds() + expiresIn) err.message
ctx = saveCredentials({
ctx,
accessToken,
expiresAt,
refreshToken,
credentialsIndex
})
const projects = await listProjects(ctx)
const message = 'Select a project:'
const choices = projects.map(project => {
return {
name: `${project.name} (${project.projectId})`,
value: project.projectId,
short: project.name
}
})
const projectId = await promptList({
message,
choices,
separator: false
})
const { projectId: id, name } = projects.find(
p => p.projectId === projectId
) )
console.log(
credentialsIndex = ctx.authConfig.credentials.findIndex( error(
cred => cred.provider === 'gcp' 'Unexpected error occurred while authenthing with Google',
err.stack
)
) )
ctx.authConfig.credentials[credentialsIndex].project = { return
id, }
name
}
writeToAuthConfigFile(ctx.authConfig)
try {
const json = await response.json()
accessToken = json.access_token
expiresIn = json.expires_in
refreshToken = json.refresh_token
} catch (err) {
debug(
'unexpected error occurred while parsing the JSON from the exchange request',
err.stack,
'got',
await response.text()
)
console.log( console.log(
ready( error(
`Credentials and project saved in ${param(humanize(getNowDir()))}.` 'Unexpected error occurred while parsing the JSON response from Google',
err.message
) )
) )
resolve(1) return
} }
})
let shouldRetry = true const now = new Date()
let portToTry = ports.shift() // `expires_in` is 3600 seconds
const expiresAt = now.setSeconds(now.getSeconds() + expiresIn)
ctx = saveCredentials({
ctx,
accessToken,
expiresAt,
refreshToken,
credentialsIndex
})
while (shouldRetry) { const projects = await listProjects(ctx)
try { const message = 'Select a project:'
await serverListen({ server, port: portToTry }) const choices = projects.map(project => {
shouldRetry = false // done, listening return {
} catch (err) { name: `${project.name} (${project.projectId})`,
if (ports.length) { value: project.projectId,
// let's try again short: project.name
portToTry = ports.shift()
} else {
// we're out of ports to try
shouldRetry = false
} }
})
const projectId = await promptList({
message,
choices,
separator: false
})
const { projectId: id, name } = projects.find(
p => p.projectId === projectId
)
credentialsIndex = ctx.authConfig.credentials.findIndex(
cred => cred.provider === 'gcp'
)
ctx.authConfig.credentials[credentialsIndex].project = {
id,
name
} }
}
if (!server.listening) { writeToAuthConfigFile(ctx.authConfig)
console.log( console.log(
error( ready(
`Make sure you have one of the following TCP ports available:`, `Credentials and project saved in ${param(humanize(getNowDir()))}.`
` ${PORTS.join(', ').replace()}`
) )
) )
return resolve(1)
} }
const query = { resolve()
client_id: CLIENT_ID, })
redirect_uri: `http://localhost:${portToTry}`,
response_type: RESPONSE_TYPE, let shouldRetry = true
scope: SCOPES.join(' '), let portToTry = ports.shift()
access_type: ACCESS_TYPE,
prompt: PROMPT_CONSENT while (shouldRetry) {
try {
await serverListen({ server, port: portToTry })
shouldRetry = false // done, listening
} catch (err) {
if (ports.length) {
// let's try again
portToTry = ports.shift()
} else {
// we're out of ports to try
shouldRetry = false
}
} }
}
opn(USER_URL + '?' + encodeQuery(query)) if (!server.listening) {
}) console.log(
} error(
`Make sure you have one of the following TCP ports available:`,
` ${PORTS.join(', ').replace()}`
)
)
return
}
const query = {
client_id: CLIENT_ID,
redirect_uri: `http://localhost:${portToTry}`,
response_type: RESPONSE_TYPE,
scope: SCOPES.join(' '),
access_type: ACCESS_TYPE,
prompt: PROMPT_CONSENT
}
opn(USER_URL + '?' + encodeQuery(query))
})
module.exports = login module.exports = login

Loading…
Cancel
Save