diff --git a/spec/AuthenticationAdapters.spec.js b/spec/AuthenticationAdapters.spec.js index d32eba0423..89eeb51231 100644 --- a/spec/AuthenticationAdapters.spec.js +++ b/spec/AuthenticationAdapters.spec.js @@ -1707,6 +1707,24 @@ describe('Apple Game Center Auth adapter', () => { expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: invalid.com'); } }); + + it('validateAuthData invalid public key http url', async () => { + const authData = { + id: 'G:1965586982', + publicKeyUrl: 'http://static.gc.apple.com/public-key/gc-prod-4.cer', + timestamp: 1565257031287, + signature: '1234', + salt: 'DzqqrQ==', + bundleId: 'cloud.xtralife.gamecenterauth', + }; + + try { + await gcenter.validateAuthData(authData); + fail(); + } catch (e) { + expect(e.message).toBe('Apple Game Center - invalid publicKeyUrl: http://static.gc.apple.com/public-key/gc-prod-4.cer'); + } + }); }); describe('phant auth adapter', () => { diff --git a/spec/batch.spec.js b/spec/batch.spec.js index b9e079cafe..f91f91a0b5 100644 --- a/spec/batch.spec.js +++ b/spec/batch.spec.js @@ -111,6 +111,28 @@ describe('batch', () => { expect(internalURL).toEqual('/classes/Object'); }); + it('should return the proper url with bad url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + 'badurl.com', + publicServerURL + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + + it('should return the proper url with bad public url provided', () => { + const originalURL = '/parse/batch'; + const internalURL = batch.makeBatchRoutingPathFunction( + originalURL, + serverURLNaked, + 'badurl.com' + )('/parse/classes/Object'); + + expect(internalURL).toEqual('/classes/Object'); + }); + it('should handle a batch request without transaction', async () => { spyOn(databaseAdapter, 'createObject').and.callThrough(); diff --git a/src/Adapters/Auth/gcenter.js b/src/Adapters/Auth/gcenter.js index 090b9fab02..322c2430d1 100644 --- a/src/Adapters/Auth/gcenter.js +++ b/src/Adapters/Auth/gcenter.js @@ -14,20 +14,23 @@ const authData = { const { Parse } = require('parse/node'); const crypto = require('crypto'); const https = require('https'); -const url = require('url'); const cache = {}; // (publicKey -> cert) cache function verifyPublicKeyUrl(publicKeyUrl) { - const parsedUrl = url.parse(publicKeyUrl); - if (parsedUrl.protocol !== 'https:') { + try { + const parsedUrl = new URL(publicKeyUrl); + if (parsedUrl.protocol !== 'https:') { + return false; + } + const hostnameParts = parsedUrl.hostname.split('.'); + const length = hostnameParts.length; + const domainParts = hostnameParts.slice(length - 2, length); + const domain = domainParts.join('.'); + return domain === 'apple.com'; + } catch(error) { return false; } - const hostnameParts = parsedUrl.hostname.split('.'); - const length = hostnameParts.length; - const domainParts = hostnameParts.slice(length - 2, length); - const domain = domainParts.join('.'); - return domain === 'apple.com'; } function convertX509CertToPEM(X509Cert) { diff --git a/src/Adapters/Auth/oauth2.js b/src/Adapters/Auth/oauth2.js index cefe7bdff2..ba1fe7bc4f 100644 --- a/src/Adapters/Auth/oauth2.js +++ b/src/Adapters/Auth/oauth2.js @@ -54,7 +54,6 @@ */ const Parse = require('parse/node').Parse; -const url = require('url'); const querystring = require('querystring'); const httpsRequest = require('./httpsRequest'); @@ -112,7 +111,7 @@ function requestTokenInfo(options, access_token) { if (!options || !options.tokenIntrospectionEndpointUrl) { throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, MISSING_URL); } - const parsedUrl = url.parse(options.tokenIntrospectionEndpointUrl); + const parsedUrl = new URL(options.tokenIntrospectionEndpointUrl); const postData = querystring.stringify({ token: access_token, }); diff --git a/src/Adapters/Storage/Postgres/PostgresConfigParser.js b/src/Adapters/Storage/Postgres/PostgresConfigParser.js index 170e76282a..d86778cf20 100644 --- a/src/Adapters/Storage/Postgres/PostgresConfigParser.js +++ b/src/Adapters/Storage/Postgres/PostgresConfigParser.js @@ -1,18 +1,16 @@ -const url = require('url'); const fs = require('fs'); function getDatabaseOptionsFromURI(uri) { const databaseOptions = {}; - const parsedURI = url.parse(uri); - const queryParams = parseQueryParams(parsedURI.query); - const authParts = parsedURI.auth ? parsedURI.auth.split(':') : []; + const parsedURI = new URL(uri); + const queryParams = parseQueryParams(parsedURI.searchParams.toString()); databaseOptions.host = parsedURI.hostname || 'localhost'; databaseOptions.port = parsedURI.port ? parseInt(parsedURI.port) : 5432; databaseOptions.database = parsedURI.pathname ? parsedURI.pathname.substr(1) : undefined; - databaseOptions.user = authParts.length > 0 ? authParts[0] : ''; - databaseOptions.password = authParts.length > 1 ? authParts[1] : ''; + databaseOptions.user = parsedURI.username; + databaseOptions.password = parsedURI.password; if (queryParams.ssl && queryParams.ssl.toLowerCase() === 'true') { databaseOptions.ssl = true; diff --git a/src/Controllers/LoggerController.js b/src/Controllers/LoggerController.js index 04d3a6d784..8ee492cf4b 100644 --- a/src/Controllers/LoggerController.js +++ b/src/Controllers/LoggerController.js @@ -1,7 +1,6 @@ import { Parse } from 'parse/node'; import AdaptableController from './AdaptableController'; import { LoggerAdapter } from '../Adapters/Logger/LoggerAdapter'; -import url from 'url'; const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000; const LOG_STRING_TRUNCATE_LENGTH = 1000; @@ -38,15 +37,16 @@ export class LoggerController extends AdaptableController { }); } - maskSensitiveUrl(urlString) { - const urlObj = url.parse(urlString, true); - const query = urlObj.query; + maskSensitiveUrl(path) { + const urlString = 'http://localhost' + path; // prepend dummy string to make a real URL + const urlObj = new URL(urlString); + const query = urlObj.searchParams; let sanitizedQuery = '?'; - for (const key in query) { + for (const [key, value] of query) { if (key !== 'password') { // normal value - sanitizedQuery += key + '=' + query[key] + '&'; + sanitizedQuery += key + '=' + value + '&'; } else { // password value, redact it sanitizedQuery += key + '=' + '********' + '&'; diff --git a/src/Controllers/index.js b/src/Controllers/index.js index 71ab5ef486..152de684fe 100644 --- a/src/Controllers/index.js +++ b/src/Controllers/index.js @@ -2,7 +2,6 @@ import authDataManager from '../Adapters/Auth'; import { ParseServerOptions } from '../Options'; import { loadAdapter } from '../Adapters/AdapterLoader'; import defaults from '../defaults'; -import url from 'url'; // Controllers import { LoggerController } from './LoggerController'; import { FilesController } from './FilesController'; @@ -220,7 +219,7 @@ export function getAuthDataManager(options: ParseServerOptions) { export function getDatabaseAdapter(databaseURI, collectionPrefix, databaseOptions) { let protocol; try { - const parsedURI = url.parse(databaseURI); + const parsedURI = new URL(databaseURI); protocol = parsedURI.protocol ? parsedURI.protocol.toLowerCase() : null; } catch (e) { /* */ diff --git a/src/ParseServerRESTController.js b/src/ParseServerRESTController.js index 9e765ff3e3..12ee0a67e5 100644 --- a/src/ParseServerRESTController.js +++ b/src/ParseServerRESTController.js @@ -1,7 +1,6 @@ const Config = require('./Config'); const Auth = require('./Auth'); const RESTController = require('parse/lib/node/RESTController'); -const URL = require('url'); const Parse = require('parse/node'); function getSessionToken(options) { @@ -38,9 +37,9 @@ function ParseServerRESTController(applicationId, router) { if (!config) { config = Config.get(applicationId); } - const serverURL = URL.parse(config.serverURL); - if (path.indexOf(serverURL.path) === 0) { - path = path.slice(serverURL.path.length, path.length); + const serverURL = new URL(config.serverURL); + if (path.indexOf(serverURL.pathname) === 0) { + path = path.slice(serverURL.pathname.length, path.length); } if (path[0] !== '/') { diff --git a/src/batch.js b/src/batch.js index 58c23ccab6..0625ef0ecc 100644 --- a/src/batch.js +++ b/src/batch.js @@ -1,5 +1,4 @@ const Parse = require('parse/node').Parse; -const url = require('url'); const path = require('path'); // These methods handle batch requests. const batchPath = '/batch'; @@ -11,11 +10,12 @@ function mountOnto(router) { }); } -function parseURL(URL) { - if (typeof URL === 'string') { - return url.parse(URL); +function parseURL(urlString) { + try { + return new URL(urlString); + } catch(error) { + return undefined; } - return undefined; } function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) { @@ -33,9 +33,9 @@ function makeBatchRoutingPathFunction(originalUrl, serverURL, publicServerURL) { return path.posix.join('/', requestPath.slice(apiPrefix.length)); }; - if (serverURL && publicServerURL && serverURL.path != publicServerURL.path) { - const localPath = serverURL.path; - const publicPath = publicServerURL.path; + if (serverURL && publicServerURL && serverURL.pathname != publicServerURL.pathname) { + const localPath = serverURL.pathname; + const publicPath = publicServerURL.pathname; // Override the api prefix apiPrefix = localPath;