From 6e48539d76ca27e6f4c6cf2ac0872970f7391fed Mon Sep 17 00:00:00 2001 From: Jonathan Lui Date: Fri, 1 May 2020 13:19:01 -0700 Subject: [PATCH] fix(v4-policy): encode special characters (#1169) * fix(v4-policy): encode special characters * test special character encoding Co-authored-by: Benjamin E. Coe --- conformance-test/v4SignedUrl.ts | 11 +++++------ src/file.ts | 4 ++-- src/util.ts | 13 +++++++++++++ test/file.ts | 24 ++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/conformance-test/v4SignedUrl.ts b/conformance-test/v4SignedUrl.ts index f263ddd45..b5e944e5c 100644 --- a/conformance-test/v4SignedUrl.ts +++ b/conformance-test/v4SignedUrl.ts @@ -220,16 +220,15 @@ describe('v4 conformance test', () => { assert.strictEqual(policy.url, testCase.policyOutput.url); const outputFields = testCase.policyOutput.fields; - const decodedPolicy = Buffer.from( - policy.fields.policy, - 'base64' - ).toString(); + const decodedPolicy = JSON.parse( + Buffer.from(policy.fields.policy, 'base64').toString() + ); assert.deepStrictEqual( decodedPolicy, - testCase.policyOutput.expectedDecodedPolicy + JSON.parse(testCase.policyOutput.expectedDecodedPolicy) ); - assert.deepStrictEqual(outputFields, testCase.policyOutput.fields); + assert.deepStrictEqual(policy.fields, outputFields); fakeTimer.restore(); }); diff --git a/src/file.ts b/src/file.ts index d5f36070f..7f3f7a8bb 100644 --- a/src/file.ts +++ b/src/file.ts @@ -63,7 +63,7 @@ import { } from '@google-cloud/common/build/src/util'; // eslint-disable-next-line @typescript-eslint/no-var-requires const duplexify: DuplexifyConstructor = require('duplexify'); -import {normalize, objectKeyToLowercase} from './util'; +import {normalize, objectKeyToLowercase, unicodeJSONStringify} from './util'; import {GaxiosError, Headers, request as gaxiosRequest} from 'gaxios'; export type GetExpirationDateResponse = [Date]; @@ -2611,7 +2611,7 @@ class File extends ServiceObject { expiration, }; - const policyString = JSON.stringify(policy); + const policyString = unicodeJSONStringify(policy); const policyBase64 = Buffer.from(policyString).toString('base64'); try { diff --git a/src/util.ts b/src/util.ts index 19d0b77ed..c2cc376e6 100644 --- a/src/util.ts +++ b/src/util.ts @@ -90,3 +90,16 @@ export function objectKeyToLowercase(object: {[key: string]: T}) { } return newObj; } + +/** + * JSON encode str, with unicode \u+ representation. + * @param {object} obj The object to encode. + * @return {string} Serialized string. + */ +export function unicodeJSONStringify(obj: object) { + return JSON.stringify(obj).replace( + /[\u0080-\uFFFF]/g, + (char: string) => + '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4) + ); +} diff --git a/test/file.ts b/test/file.ts index 72b40e6d9..a7c4420f7 100644 --- a/test/file.ts +++ b/test/file.ts @@ -2941,6 +2941,30 @@ describe('File', () => { ); }); + it('should encode special characters in policy', done => { + CONFIG = { + fields: { + 'x-goog-meta-foo': 'bår', + }, + ...CONFIG, + }; + + file.generateSignedPostPolicyV4( + CONFIG, + (err: Error, res: SignedPostPolicyV4Output) => { + assert.ifError(err); + + assert.strictEqual(res.fields['x-goog-meta-foo'], 'bår'); + const decodedPolicy = Buffer.from( + res.fields.policy, + 'base64' + ).toString('utf-8'); + assert(decodedPolicy.includes('"x-goog-meta-foo":"b\\u00e5r"')); + done(); + } + ); + }); + it('should not include fields with x-ignore- prefix in conditions', done => { CONFIG = { fields: {