-
Notifications
You must be signed in to change notification settings - Fork 938
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move API router handlers into their own files
- Loading branch information
Showing
4 changed files
with
199 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
const express = require('express'); | ||
const cookieParser = require('cookie-parser'); | ||
|
||
const PORT = 3500; | ||
const app = express(); | ||
app.use(cookieParser()); | ||
|
||
app.get('/api/log', (req, res) => { | ||
console.log('api-server log:', req.cookies); | ||
res | ||
.set({ | ||
'Access-Control-Allow-Origin': 'http://localhost:3000', | ||
'Access-Control-Allow-Credentials': true, | ||
}) | ||
.status(200) | ||
.json({ | ||
req: { | ||
method: req.method, | ||
cookies: req.cookies || null, | ||
cookieHeader: req.get('Cookie'), | ||
}, | ||
}) | ||
.end(); | ||
}); | ||
|
||
app.listen(PORT, () => { | ||
console.log(`api-server listening on ${PORT}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
const crypto = require('crypto'); | ||
|
||
const CLIENT_ID = process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID; | ||
const ROOT_URL = process.env.REACT_APP_CANONICAL_ROOT_URL; | ||
const CONSOLE_URL = | ||
process.env.SERVER_SHARETRIBE_CONSOLE_URL || 'https://flex-console.sharetribe.com'; | ||
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true'; | ||
|
||
// redirect_uri param used when initiating a login as authentication flow and | ||
// when requesting a token using an authorization code | ||
const loginAsRedirectUri = `${ROOT_URL.replace(/\/$/, '')}/api/login-as`; | ||
|
||
// Cookies used for authorization code authentication. | ||
const stateKey = `st-${CLIENT_ID}-oauth2State`; | ||
const codeVerifierKey = `st-${CLIENT_ID}-pkceCodeVerifier`; | ||
|
||
/** | ||
* Makes a base64 string URL friendly by | ||
* replacing unaccepted characters. | ||
*/ | ||
const urlifyBase64 = base64Str => | ||
base64Str | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_') | ||
.replace(/=/g, ''); | ||
|
||
// Initiates an authorization code authentication flow. This authentication flow | ||
// enables marketplace operators that have an ongoing Console session to log | ||
// into their marketplace as a user of the marketplace. | ||
// | ||
// The authorization code is requested from Console and it is used to request a | ||
// token from the Flex Auth API. | ||
// | ||
// This endpoint will return a 302 to Console which requests the authorization | ||
// code. Console returns a 302 with the code to the `redirect_uri` that is | ||
// passed in this response. The request to the redirect URI is handled with the | ||
// `/login-as` endpoint. | ||
module.exports = (req, res) => { | ||
const userId = req.query.user_id; | ||
|
||
if (!userId) { | ||
return res.status(400).send('Missing query parameter: user_id.'); | ||
} | ||
if (!ROOT_URL) { | ||
return res.status(409).send('Marketplace canonical root URL is missing.'); | ||
} | ||
|
||
const state = urlifyBase64(crypto.randomBytes(32).toString('base64')); | ||
const codeVerifier = urlifyBase64(crypto.randomBytes(32).toString('base64')); | ||
const hash = crypto | ||
.createHash('sha256') | ||
.update(codeVerifier) | ||
.digest('base64'); | ||
const codeChallenge = urlifyBase64(hash); | ||
const authorizeServerUrl = `${CONSOLE_URL}/api/authorize-as`; | ||
|
||
const location = `${authorizeServerUrl}?\ | ||
response_type=code&\ | ||
client_id=${CLIENT_ID}&\ | ||
redirect_uri=${loginAsRedirectUri}&\ | ||
user_id=${userId}&\ | ||
state=${state}&\ | ||
code_challenge=${codeChallenge}&\ | ||
code_challenge_method=S256`; | ||
|
||
const cookieOpts = { | ||
maxAge: 1000 * 30, // 30 seconds | ||
secure: USING_SSL, | ||
}; | ||
|
||
res.cookie(stateKey, state, cookieOpts); | ||
res.cookie(codeVerifierKey, codeVerifier, cookieOpts); | ||
return res.redirect(location); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
const http = require('http'); | ||
const https = require('https'); | ||
const sharetribeSdk = require('sharetribe-flex-sdk'); | ||
const Decimal = require('decimal.js'); | ||
|
||
const CLIENT_ID = process.env.REACT_APP_SHARETRIBE_SDK_CLIENT_ID; | ||
const ROOT_URL = process.env.REACT_APP_CANONICAL_ROOT_URL; | ||
const BASE_URL = process.env.REACT_APP_SHARETRIBE_SDK_BASE_URL; | ||
const TRANSIT_VERBOSE = process.env.REACT_APP_SHARETRIBE_SDK_TRANSIT_VERBOSE === 'true'; | ||
const USING_SSL = process.env.REACT_APP_SHARETRIBE_USING_SSL === 'true'; | ||
|
||
// redirect_uri param used when initiating a login as authentication flow and | ||
// when requesting a token using an authorization code | ||
const loginAsRedirectUri = `${ROOT_URL.replace(/\/$/, '')}/api/login-as`; | ||
|
||
// Instantiate HTTP(S) Agents with keepAlive set to true. | ||
// This will reduce the request time for consecutive requests by | ||
// reusing the existing TCP connection, thus eliminating the time used | ||
// for setting up new TCP connections. | ||
const httpAgent = new http.Agent({ keepAlive: true }); | ||
const httpsAgent = new https.Agent({ keepAlive: true }); | ||
|
||
// Cookies used for authorization code authentication. | ||
const stateKey = `st-${CLIENT_ID}-oauth2State`; | ||
const codeVerifierKey = `st-${CLIENT_ID}-pkceCodeVerifier`; | ||
|
||
/** | ||
* Makes a base64 string URL friendly by | ||
* replacing unaccepted characters. | ||
*/ | ||
const urlifyBase64 = base64Str => | ||
base64Str | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_') | ||
.replace(/=/g, ''); | ||
|
||
// Works as the redirect_uri passed in an authorization code request. Receives | ||
// an authorization code and uses that to log in and redirect to the landing | ||
// page. | ||
module.exports = (req, res) => { | ||
const { code, state, error } = req.query; | ||
const storedState = req.cookies[stateKey]; | ||
|
||
if (state !== storedState) { | ||
res.status(401).send('Invalid state parameter.'); | ||
return; | ||
} | ||
|
||
if (error) { | ||
res.status(401).send(`Failed to authorize as a user, error: ${error}.`); | ||
return; | ||
} | ||
|
||
const codeVerifier = req.cookies[codeVerifierKey]; | ||
|
||
// clear state and code verifier cookies | ||
res.clearCookie(stateKey, { secure: USING_SSL }); | ||
res.clearCookie(codeVerifierKey, { secure: USING_SSL }); | ||
|
||
const baseUrl = BASE_URL ? { baseUrl: BASE_URL } : {}; | ||
const tokenStore = sharetribeSdk.tokenStore.expressCookieStore({ | ||
clientId: CLIENT_ID, | ||
req, | ||
res, | ||
secure: USING_SSL, | ||
}); | ||
|
||
const sdk = sharetribeSdk.createInstance({ | ||
transitVerbose: TRANSIT_VERBOSE, | ||
clientId: CLIENT_ID, | ||
httpAgent: httpAgent, | ||
httpsAgent: httpsAgent, | ||
tokenStore, | ||
typeHandlers: [ | ||
{ | ||
type: sharetribeSdk.types.BigDecimal, | ||
customType: Decimal, | ||
writer: v => new sharetribeSdk.types.BigDecimal(v.toString()), | ||
reader: v => new Decimal(v.value), | ||
}, | ||
], | ||
...baseUrl, | ||
}); | ||
|
||
sdk | ||
.login({ | ||
code, | ||
redirect_uri: loginAsRedirectUri, | ||
code_verifier: codeVerifier, | ||
}) | ||
.then(() => res.redirect('/')) | ||
.catch(() => res.status(401).send('Unable to authenticate as a user')); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters