Skip to content

Commit

Permalink
feat: monitor whether API Authentication has been enabled (#4235)
Browse files Browse the repository at this point in the history
* feat: monitor whether API Authentication has been enabled

* feat: inject `ONEGRAPH_AUTHLIFY_TOKEN` in the poller as well

* fix: only poll if graph enabled

* fix: simplify env variable injection

* fix: remove await

* fix: remove more unused async / awaits

Co-authored-by: Erez Rokah <erezrokah@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 9, 2022
1 parent cb5f302 commit 437c225
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 67 deletions.
47 changes: 6 additions & 41 deletions src/commands/dev/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const {
detectServerSettings,
error,
exit,
generateAuthlifyJWT,
getSiteInformation,
injectEnvVariables,
log,
Expand Down Expand Up @@ -265,27 +264,7 @@ const dev = async (options, command) => {
}

const startNetlifyGraphWatcher = Boolean(options.graph)
let authlifyJWT

if (startNetlifyGraphWatcher) {
const netlifyToken = await command.authenticate()
authlifyJWT = generateAuthlifyJWT(netlifyToken, siteInfo.authlify_token_id, site.id)
}

await injectEnvVariables({
env: Object.assign(
command.netlify.cachedConfig.env,
authlifyJWT == null
? {}
: {
ONEGRAPH_AUTHLIFY_TOKEN: {
sources: ['general'],
value: authlifyJWT,
},
},
),
site,
})
await injectEnvVariables({ env: command.netlify.cachedConfig.env, site })

const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({
// inherited from base command --offline
Expand All @@ -306,28 +285,14 @@ const dev = async (options, command) => {

command.setAnalyticsPayload({ projectType: settings.framework || 'custom', live: options.live })

let configWithAuthlify

if (siteInfo.authlify_token_id) {
const netlifyToken = command.authenticate()
// Only inject the authlify config if a token ID exists. This prevents
// calling command.authenticate() (which opens a browser window) if the
// user hasn't enabled API Authentication
configWithAuthlify = Object.assign(config, {
authlify: {
netlifyToken,
authlifyTokenId: siteInfo.authlify_token_id,
siteId: site.id,
},
})
} else {
configWithAuthlify = config
}

await startFunctionsServer({
config: configWithAuthlify,
api,
command,
config,
isGraphEnabled: startNetlifyGraphWatcher,
settings,
site,
siteInfo,
siteUrl,
capabilities,
timeouts,
Expand Down
2 changes: 2 additions & 0 deletions src/commands/functions/functions-serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ const functionsServe = async (options, command) => {

await startFunctionsServer({
config,
api,
settings: { functions: functionsDir, functionsPort },
site,
siteInfo,
siteUrl,
capabilities,
timeouts,
Expand Down
79 changes: 56 additions & 23 deletions src/lib/functions/server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// @ts-check
const process = require('process')

const jwtDecode = require('jwt-decode')

const {
CLOCKWORK_USERAGENT,
NETLIFYDEVERR,
NETLIFYDEVLOG,
error: errorExit,
generateAuthlifyJWT,
generateNetlifyGraphJWT,
getInternalFunctionsDir,
log,
} = require('../../utils')
Expand Down Expand Up @@ -45,7 +47,49 @@ const buildClientContext = function (headers) {
}
}

const createHandler = function ({ config, functionsRegistry }) {
const startPollingForAPIAuthentication = async function (options) {
const { api, command, config, site, siteInfo } = options
const frequency = 5000

const helper = async (maybeSiteData) => {
const siteData = await (maybeSiteData || api.getSite({ siteId: site.id }))
const authlifyTokenId = siteData && siteData.authlify_token_id

const existingAuthlifyTokenId = config && config.netlifyGraphConfig && config.netlifyGraphConfig.authlifyTokenId
if (authlifyTokenId && authlifyTokenId !== existingAuthlifyTokenId) {
const netlifyToken = await command.authenticate()
// Only inject the authlify config if a token ID exists. This prevents
// calling command.authenticate() (which opens a browser window) if the
// user hasn't enabled API Authentication
const netlifyGraphConfig = {
netlifyToken,
authlifyTokenId: siteData.authlify_token_id,
siteId: site.id,
}
config.netlifyGraphConfig = netlifyGraphConfig

const netlifyGraphJWT = generateNetlifyGraphJWT(netlifyGraphConfig)

if (netlifyGraphJWT != null) {
process.env.ONEGRAPH_AUTHLIFY_TOKEN = netlifyGraphJWT
}
} else {
delete config.authlify
}

setTimeout(helper, frequency)
}

await helper(siteInfo)
}

const createHandler = function (options) {
const { config, functionsRegistry } = options

if (options.isGraphEnabled) {
startPollingForAPIAuthentication(options)
}

return async function handler(request, response) {
// handle proxies without path re-writes (http-servr)
const cleanPath = request.path.replace(/^\/.netlify\/(functions|builders)/, '')
Expand Down Expand Up @@ -107,8 +151,10 @@ const createHandler = function ({ config, functionsRegistry }) {
}

if (config && config.authlify && config.authlify.authlifyTokenId != null) {
const { authlifyTokenId, netlifyToken, siteId } = config.authlify
event.authlifyToken = generateAuthlifyJWT(netlifyToken, authlifyTokenId, siteId)
// XXX(anmonteiro): this name is deprecated. Delete after 3/31/2022
const jwt = generateNetlifyGraphJWT(config.netlifyGraphConfig)
event.authlifyToken = jwt
event.netlifyGraphToken = jwt
}

const clientContext = buildClientContext(request.headers) || {}
Expand Down Expand Up @@ -160,14 +206,15 @@ const createHandler = function ({ config, functionsRegistry }) {
}
}

const getFunctionsServer = function ({ buildersPrefix, config, functionsPrefix, functionsRegistry, siteUrl }) {
const getFunctionsServer = function (options) {
const { buildersPrefix = '', functionsPrefix = '', functionsRegistry, siteUrl } = options
// performance optimization, load express on demand
// eslint-disable-next-line node/global-require
const express = require('express')
// eslint-disable-next-line node/global-require
const expressLogging = require('express-logging')
const app = express()
const functionHandler = createHandler({ config, functionsRegistry })
const functionHandler = createHandler(options)

app.set('query parser', 'simple')

Expand Down Expand Up @@ -195,16 +242,8 @@ const getFunctionsServer = function ({ buildersPrefix, config, functionsPrefix,
return app
}

const startFunctionsServer = async ({
buildersPrefix = '',
capabilities,
config,
functionsPrefix = '',
settings,
site,
siteUrl,
timeouts,
}) => {
const startFunctionsServer = async (options) => {
const { capabilities, config, settings, site, siteUrl, timeouts } = options
const internalFunctionsDir = await getInternalFunctionsDir({ base: site.root })

// The order of the function directories matters. Leftmost directories take
Expand All @@ -223,13 +262,7 @@ const startFunctionsServer = async ({

await functionsRegistry.scan(functionsDirectories)

const server = getFunctionsServer({
config,
functionsRegistry,
siteUrl,
functionsPrefix,
buildersPrefix,
})
const server = getFunctionsServer(Object.assign(options, { functionsRegistry }))

await startWebServer({ server, settings })
}
Expand Down
6 changes: 3 additions & 3 deletions src/utils/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,12 @@ const acquirePort = async ({ configuredPort, defaultPort, errorMessage }) => {
return acquiredPort
}

// Generates an Authlify JWT with the following claims:
// Generates a Netlify Graph JWT with the following claims:
// - site_id
// - netlify_token -- the bearer token for the Netlify API
// - authlify_token_id -- the authlify token ID stored for the site after
// enabling API Authentication.
const generateAuthlifyJWT = (netlifyToken, authlifyTokenId, siteId) => {
const generateNetlifyGraphJWT = ({ authlifyTokenId, netlifyToken, siteId }) => {
const claims = {
netlify_token: netlifyToken,
authlify_token_id: authlifyTokenId,
Expand All @@ -219,5 +219,5 @@ module.exports = {
getSiteInformation,
injectEnvVariables,
acquirePort,
generateAuthlifyJWT,
generateNetlifyGraphJWT,
}

1 comment on commit 437c225

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

Package size: 438 MB

Please sign in to comment.