Skip to content

Commit a6ef06c

Browse files
committed
fix bug: if expiry date object has >= 500 ms then a rounding error occurs and is thrown. added tests to replicate.
1 parent 2c967f6 commit a6ef06c

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

src/signer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ export class URLSigner {
416416
throw new Error(ExceptionMessages.EXPIRATION_DATE_PAST);
417417
}
418418

419-
return Math.round(expiresInMSeconds / 1000); // The API expects seconds.
419+
return Math.floor(expiresInMSeconds / 1000); // The API expects seconds.
420420
}
421421

422422
parseAccessibleAt(accessibleAt?: string | number | Date): number {

system-test/storage.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3290,6 +3290,31 @@ describe('storage', () => {
32903290
assert.strictEqual(body, localFile.toString());
32913291
});
32923292

3293+
it('should not throw with expiration of exactly 7 days', async () => {
3294+
const ACCESSIBLE_AT = new Date().setMilliseconds(999).valueOf();
3295+
const SEVEN_DAYS_IN_SECONDS = 7 * 24 * 60 * 60;
3296+
const SEVEN_DAYS_IN_MS = SEVEN_DAYS_IN_SECONDS * 1000;
3297+
await assert.doesNotReject(
3298+
async () => {
3299+
await file.getSignedUrl({
3300+
version: 'v4',
3301+
action: 'read',
3302+
accessibleAt: ACCESSIBLE_AT,
3303+
expires: ACCESSIBLE_AT + SEVEN_DAYS_IN_MS,
3304+
virtualHostedStyle: true,
3305+
});
3306+
},
3307+
err => {
3308+
assert(err instanceof Error);
3309+
assert.strictEqual(
3310+
err.message,
3311+
`Max allowed expiration is seven days (${SEVEN_DAYS_IN_SECONDS} seconds).`
3312+
);
3313+
return true;
3314+
}
3315+
);
3316+
});
3317+
32933318
it('should create a signed read url with accessibleAt in the past', async () => {
32943319
const [signedReadUrl] = await file.getSignedUrl({
32953320
version: 'v4',

test/signer.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
SignerExceptionMessages,
3030
} from '../src/signer';
3131
import {encodeURI, formatAsUTCISO, qsStringify} from '../src/util';
32-
import {ExceptionMessages} from '../src/storage';
32+
import {Storage, ExceptionMessages} from '../src/storage';
3333
import {OutgoingHttpHeaders} from 'http';
3434

3535
interface SignedUrlArgs {
@@ -56,7 +56,7 @@ describe('signer', () => {
5656
let bucket: BucketI;
5757
let file: FileI;
5858

59-
const NOW = new Date('2019-03-18T00:00:00Z');
59+
const NOW = new Date('2019-03-18T00:00:00.999Z');
6060
let fakeTimers: sinon.SinonFakeTimers;
6161

6262
beforeEach(() => (fakeTimers = sinon.useFakeTimers(NOW)));
@@ -554,7 +554,7 @@ describe('signer', () => {
554554
signer = new URLSigner(authClient, bucket, file);
555555
CONFIG = {
556556
method: 'GET',
557-
expiration: Math.floor((NOW.valueOf() + 2000) / 1000),
557+
expiration: (NOW.valueOf() + 2000) / 1000,
558558
bucket: bucket.name,
559559
};
560560
});
@@ -573,6 +573,52 @@ describe('signer', () => {
573573
);
574574
});
575575

576+
it('should not throw with expiration of exactly 7 days', async () => {
577+
const file = new Storage({
578+
projectId: 'xxxx',
579+
credentials: {
580+
type: 'service_account',
581+
private_key: crypto.generateKeyPairSyn c('rsa', {
582+
modulusLength: 512,
583+
publicKeyEncoding: {
584+
type: 'spki',
585+
format: 'pem',
586+
},
587+
privateKeyEncoding: {
588+
type: 'pkcs8',
589+
format: 'pem',
590+
},
591+
}).privateKey,
592+
client_email: 'xxxx',
593+
client_id: 'xxx',
594+
},
595+
})
596+
.bucket(BUCKET_NAME)
597+
.file(FILE_NAME);
598+
const ACCESSIBLE_AT = NOW.valueOf();
599+
const SEVEN_DAYS_IN_SECONDS = 7 * 24 * 60 * 60;
600+
const SEVEN_DAYS_IN_MS = SEVEN_DAYS_IN_SECONDS * 1000;
601+
await assert.doesNotReject(
602+
async () => {
603+
await file.getSignedUrl({
604+
version: 'v4',
605+
action: 'read',
606+
accessibleAt: ACCESSIBLE_AT,
607+
expires: ACCESSIBLE_AT + SEVEN_DAYS_IN_MS,
608+
virtualHostedStyle: true,
609+
});
610+
},
611+
err => {
612+
assert(err instanceof Error);
613+
assert.strictEqual(
614+
err.message,
615+
`Max allowed expiration is seven days (${SEVEN_DAYS_IN_SECONDS} seconds).`
616+
);
617+
return true;
618+
}
619+
);
620+
});
621+
576622
describe('headers', () => {
577623
it('should add path-styled host header', async () => {
578624
const getCanonicalHeaders = sandbox
@@ -988,7 +1034,7 @@ describe('signer', () => {
9881034

9891035
it('returns expiration date in seconds', () => {
9901036
const expires = signer.parseExpires(NOW);
991-
assert.strictEqual(expires, Math.round(NOW.valueOf() / 1000));
1037+
assert.strictEqual(expires, Math.floor(NOW.valueOf() / 1000));
9921038
});
9931039
});
9941040
});

0 commit comments

Comments
 (0)