Skip to content

Commit

Permalink
Merge pull request #95 from sharetribe/update-v4.5.0-from-upstream
Browse files Browse the repository at this point in the history
Update v4.5.0 from upstream
  • Loading branch information
Gnito authored Jun 4, 2020
2 parents e1b17fb + d8c1018 commit caa0907
Show file tree
Hide file tree
Showing 10 changed files with 472 additions and 248 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ https://github.com/sharetribe/flex-template-web/

## Upcoming version 2020-XX-XX

## [v6.6.0] 2020-06-04

### Updates from upstream

- [fix] In some situations, ProfileMenu has began to overflow on TopbarDesktop.
[#1290](https://github.com/sharetribe/ftw-daily/pull/1290)
- [change] Update dependencies (patch updates only)
[#1291](https://github.com/sharetribe/ftw-daily/pull/1291)
- [change] Refactor server API routes into separate files.
[#1294](https://github.com/sharetribe/ftw-daily/pull/1294)
- [change] Start the backend API router in dev mode with a dev server.
[#1297](https://github.com/sharetribe/ftw-daily/pull/1297)

[v6.6.0]: https://github.com/sharetribe/flex-template-web/compare/v6.5.1...v6.6.0

## [v6.5.1] 2020-05-13

- [fix] Check length of `selectedConfigOptions` in `SectionFeaturesMaybe` to choose between one and
Expand Down
30 changes: 17 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app",
"version": "6.5.1",
"version": "6.6.0",
"private": true,
"license": "Apache-2.0",
"dependencies": {
Expand All @@ -9,13 +9,13 @@
"@sentry/browser": "5.7.1",
"@sentry/node": "5.7.1",
"array-includes": "^3.0.3",
"array.prototype.find": "^2.0.4",
"array.prototype.find": "^2.1.1",
"autosize": "^4.0.0",
"basic-auth": "^2.0.1",
"body-parser": "^1.18.3",
"classnames": "^2.2.6",
"compression": "^1.7.4",
"cookie-parser": "^1.4.4",
"cookie-parser": "^1.4.5",
"core-js": "^3.1.4",
"decimal.js": "10.2.0",
"dotenv": "6.2.0",
Expand All @@ -24,17 +24,17 @@
"express-enforces-ssl": "^1.1.0",
"express-sitemap": "^1.8.0",
"final-form": "^4.18.5",
"final-form-arrays": "^3.0.0",
"full-icu": "^1.3.0",
"final-form-arrays": "^3.0.2",
"full-icu": "^1.3.1",
"helmet": "^3.21.2",
"intl-pluralrules": "^1.0.3",
"jstimezonedetect": "^1.0.7",
"lodash": "^4.17.14",
"mapbox-gl-multitouch": "^1.0.3",
"moment": "^2.22.2",
"moment-timezone": "^0.5.26",
"object.entries": "^1.0.4",
"object.values": "^1.0.4",
"object.entries": "^1.1.1",
"object.values": "^1.1.1",
"path-to-regexp": "^3.0.0",
"prop-types": "^15.7.2",
"query-string": "^5.1.1",
Expand All @@ -45,14 +45,14 @@
"react-final-form": "^6.3.0",
"react-final-form-arrays": "^3.1.1",
"react-google-maps": "^9.4.5",
"react-helmet-async": "^1.0.2",
"react-helmet-async": "^1.0.6",
"react-intl": "^3.1.13",
"react-moment-proptypes": "^1.6.0",
"react-redux": "^7.1.1",
"react-router-dom": "^5.0.1",
"redux": "^4.0.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"seedrandom": "^3.0.3",
"seedrandom": "^3.0.5",
"sharetribe-flex-sdk": "^1.9.1",
"sharetribe-scripts": "3.1.1",
"smoothscroll-polyfill": "^0.4.0",
Expand All @@ -61,11 +61,12 @@
},
"devDependencies": {
"babel-jest": "24.9.0",
"bfj": "^7.0.1",
"bfj": "^7.0.2",
"chalk": "^2.4.1",
"concurrently": "^5.2.0",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.12.0",
"enzyme-to-json": "^3.3.5",
"enzyme-to-json": "^3.4.4",
"inquirer": "^7.0.0",
"nodemon": "^1.17.2",
"prettier": "^1.18.2"
Expand All @@ -86,7 +87,10 @@
"audit": "yarn audit --json | node scripts/audit.js",
"clean": "rm -rf build/*",
"config": "node scripts/config.js",
"dev": "node scripts/config.js --check && sharetribe-scripts start",
"config-check": "node scripts/config.js --check",
"dev-frontend": "sharetribe-scripts start",
"dev-backend": "DEV_API_SERVER_PORT=3500 nodemon server/apiServer.js",
"dev": "yarn run config-check&&concurrently --kill-others \"yarn run dev-frontend\" \"yarn run dev-backend\"",
"build": "sharetribe-scripts build",
"format": "prettier --write '**/*.{js,css}'",
"format-ci": "prettier --list-different '**/*.{js,css}'",
Expand Down
74 changes: 74 additions & 0 deletions server/api/initiate-login-as.js
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);
};
93 changes: 93 additions & 0 deletions server/api/login-as.js
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'));
};
Loading

0 comments on commit caa0907

Please sign in to comment.