Skip to content
This repository was archived by the owner on Jan 20, 2025. It is now read-only.

Commit 55e3961

Browse files
reorganize project
1 parent 5490b32 commit 55e3961

20 files changed

+141
-123
lines changed
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: "addToDate()"
3+
---
4+
5+
# `addToDate()`
6+
7+
Creates a new `Date` by adding the provided time-span to the one provided. Supports negative time spans.
8+
9+
## Definition
10+
11+
```ts
12+
//$ TimeSpan=/reference/main/TimeSpan
13+
function createDate(date: Date, timeSpan: $$TimeSpan): Date;
14+
```
15+
16+
### Parameters
17+
18+
- `date`
19+
- `timeSpan`
20+
21+
## Example
22+
23+
```ts
24+
import { addToDate, TimeSpan } from "oslo";
25+
26+
const tomorrow = addToDate(new Date(), new TimeSpan(1, "d"));
27+
```

docs/pages/reference/main/createDate.md

-26
This file was deleted.

docs/pages/reference/main/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Provides basic utilities used by other modules.
88

99
## Functions
1010

11-
- [`createDate()`](/reference/main/createDate)
11+
- [`addToDate()`](/reference/main/addToDate)
1212
- [`isWithinExpirationDate()`](/reference/main/isWithinExpirationDate)
1313

1414
## Classes

src/crypto/bytes.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { expect, test } from "vitest";
2+
import { constantTimeEqual } from "./bytes.js";
3+
4+
test("compareBytes()", () => {
5+
const randomBytes = new Uint8Array(32);
6+
crypto.getRandomValues(randomBytes);
7+
expect(constantTimeEqual(randomBytes, randomBytes)).toBe(true);
8+
const anotherRandomBytes = new Uint8Array(32);
9+
crypto.getRandomValues(anotherRandomBytes);
10+
expect(constantTimeEqual(randomBytes, anotherRandomBytes)).toBe(false);
11+
expect(constantTimeEqual(new Uint8Array(0), new Uint8Array(1))).toBe(false);
12+
});

src/crypto/bytes.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
2+
if (a.length !== b.length) {
3+
return false;
4+
}
5+
let c = 0;
6+
for (let i = 0; i < a.length; i++) {
7+
c |= a[i]! ^ b[i]!;
8+
}
9+
return c === 0;
10+
}

src/crypto/index.ts

+3-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
export { ECDSA } from "./ecdsa.js";
2-
export { HMAC } from "./hmac.js";
3-
export { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";
1+
export { ECDSA, HMAC, RSASSAPKCS1v1_5, RSASSAPSS } from "./signing-algorithm/index.js";
42
export { sha1, sha256, sha384, sha512 } from "./sha/index.js";
53
export {
64
random,
@@ -9,21 +7,6 @@ export {
97
alphabet,
108
generateRandomBoolean
119
} from "./random.js";
10+
export { constantTimeEqual } from "./bytes.js";
1211

13-
export type { ECDSACurve } from "./ecdsa.js";
14-
15-
export interface KeyPair {
16-
publicKey: Uint8Array;
17-
privateKey: Uint8Array;
18-
}
19-
20-
export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
21-
if (a.length !== b.length) {
22-
return false;
23-
}
24-
let c = 0;
25-
for (let i = 0; i < a.length; i++) {
26-
c |= a[i]! ^ b[i]!;
27-
}
28-
return c === 0;
29-
}
12+
export type { SigningAlgorithm, KeyPair, ECDSACurve } from "./signing-algorithm/index.js";

src/crypto/ecdsa.test.ts src/crypto/signing-algorithm/ecdsa.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { describe, test, expect } from "vitest";
2-
import { ECDSA } from "./index.js";
2+
import { ECDSA } from "../index.js";
33

44
import type { ECDSACurve } from "./ecdsa.js";
5-
import type { SHAHash } from "./sha/index.js";
5+
import type { SHAHash } from "../sha/index.js";
66

77
interface TestCase {
88
hash: SHAHash;

src/crypto/ecdsa.ts src/crypto/signing-algorithm/ecdsa.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { KeyPair } from "./index.js";
2-
import type { SHAHash } from "./sha/index.js";
1+
import type { SHAHash } from "../sha/index.js";
2+
import type { SigningAlgorithm, KeyPair } from "./shared.js";
33

44
export type ECDSACurve = "P-256" | "P-384" | "P-521";
55

6-
export class ECDSA {
6+
export class ECDSA implements SigningAlgorithm {
77
private hash: SHAHash;
88
private curve: ECDSACurve;
99

src/crypto/hmac.test.ts src/crypto/signing-algorithm/hmac.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, test, expect } from "vitest";
2-
import { HMAC } from "./index.js";
2+
import { HMAC } from "../index.js";
33

4-
import type { SHAHash } from "./sha/index.js";
4+
import type { SHAHash } from "../sha/index.js";
55

66
interface TestCase {
77
hash: SHAHash;

src/crypto/hmac.ts src/crypto/signing-algorithm/hmac.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import type { SHAHash } from "./sha/index.js";
1+
import type { SigningAlgorithm } from "./shared.js";
2+
import type { SHAHash } from "../sha/index.js";
23

3-
export class HMAC {
4+
export class HMAC implements SigningAlgorithm {
45
private hash: SHAHash;
56
constructor(hash: SHAHash) {
67
this.hash = hash;

src/crypto/signing-algorithm/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export { ECDSA } from "./ecdsa.js";
2+
export { HMAC } from "./hmac.js";
3+
export { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";
4+
5+
export type { ECDSACurve } from "./ecdsa.js";
6+
7+
export type { SigningAlgorithm, KeyPair } from "./shared.js";

src/crypto/rsa.test.ts src/crypto/signing-algorithm/rsa.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, test, expect } from "vitest";
22
import { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";
33

4-
import type { SHAHash } from "./sha/index.js";
4+
import type { SHAHash } from "../sha/index.js";
55

66
interface TestCase {
77
hash: SHAHash;

src/crypto/rsa.ts src/crypto/signing-algorithm/rsa.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { KeyPair } from "./index.js";
2-
import type { SHAHash } from "./sha/index.js";
1+
import type { KeyPair, SigningAlgorithm } from "./shared.js";
2+
import type { SHAHash } from "../sha/index.js";
33

4-
export class RSASSAPKCS1v1_5 {
4+
export class RSASSAPKCS1v1_5 implements SigningAlgorithm {
55
private hash: SHAHash;
66
constructor(hash: SHAHash) {
77
this.hash = hash;
@@ -132,12 +132,12 @@ export class RSASSAPSS {
132132
return signature;
133133
}
134134

135-
public async generateKeyPair(modulusLength?: 2048 | 4096): Promise<KeyPair> {
135+
public async generateKeyPair(options?: { modulusLength?: 2048 | 4096 }): Promise<KeyPair> {
136136
const cryptoKeyPair = await crypto.subtle.generateKey(
137137
{
138138
name: "RSA-PSS",
139139
hash: this.hash,
140-
modulusLength: modulusLength ?? 2048,
140+
modulusLength: options?.modulusLength ?? 2048,
141141
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
142142
},
143143
true,
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export interface SigningAlgorithm {
2+
sign(key: Uint8Array, data: Uint8Array): Promise<Uint8Array>;
3+
verify(key: Uint8Array, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
4+
}
5+
6+
export interface KeyPair {
7+
publicKey: Uint8Array;
8+
privateKey: Uint8Array;
9+
}

src/index.ts

+2-45
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,3 @@
1-
export type TimeSpanUnit = "ms" | "s" | "m" | "h" | "d" | "w";
1+
export { TimeSpan, isWithinExpirationDate, addToDate } from "./time.js";
22

3-
export class TimeSpan {
4-
constructor(value: number, unit: TimeSpanUnit) {
5-
this.value = value;
6-
this.unit = unit;
7-
}
8-
9-
public value: number;
10-
public unit: TimeSpanUnit;
11-
12-
public milliseconds(): number {
13-
if (this.unit === "ms") {
14-
return this.value;
15-
}
16-
if (this.unit === "s") {
17-
return this.value * 1000;
18-
}
19-
if (this.unit === "m") {
20-
return this.value * 1000 * 60;
21-
}
22-
if (this.unit === "h") {
23-
return this.value * 1000 * 60 * 60;
24-
}
25-
if (this.unit === "d") {
26-
return this.value * 1000 * 60 * 60 * 24;
27-
}
28-
return this.value * 1000 * 60 * 60 * 24 * 7;
29-
}
30-
31-
public seconds(): number {
32-
return this.milliseconds() / 1000;
33-
}
34-
35-
public transform(x: number): TimeSpan {
36-
return new TimeSpan(Math.round(this.milliseconds() * x), "ms");
37-
}
38-
}
39-
40-
export function isWithinExpirationDate(date: Date): boolean {
41-
return Date.now() < date.getTime();
42-
}
43-
44-
export function createDate(timeSpan: TimeSpan): Date {
45-
return new Date(Date.now() + timeSpan.milliseconds());
46-
}
3+
export type { TimeSpanUnit } from "./time.js";

src/jwt/index.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { describe, test, expect } from "vitest";
22
import { createJWT, parseJWT, validateJWT } from "./index.js";
33

4-
import { HMAC } from "../crypto/hmac.js";
5-
import { ECDSA } from "../crypto/ecdsa.js";
6-
import { RSASSAPKCS1v1_5, RSASSAPSS } from "../crypto/rsa.js";
4+
import { HMAC } from "../crypto/signing-algorithm/hmac.js";
5+
import { ECDSA } from "../crypto/signing-algorithm/ecdsa.js";
6+
import { RSASSAPKCS1v1_5, RSASSAPSS } from "../crypto/signing-algorithm/rsa.js";
77
import { TimeSpan } from "../index.js";
88

99
test.each(["ES256", "ES384", "ES512"] as const)(

src/jwt/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { base64url } from "../encoding/index.js";
33
import { isWithinExpirationDate } from "../index.js";
44

55
import type { TimeSpan } from "../index.js";
6+
import type { SigningAlgorithm } from "../crypto/index.js";
67

78
export type JWTAlgorithm =
89
| "HS256"
@@ -235,7 +236,7 @@ export interface JWT extends JWTProperties {
235236
parts: [header: string, payload: string, signature: string];
236237
}
237238

238-
function getAlgorithm(algorithm: JWTAlgorithm): ECDSA | HMAC | RSASSAPKCS1v1_5 | RSASSAPSS {
239+
function getAlgorithm(algorithm: JWTAlgorithm): SigningAlgorithm {
239240
if (algorithm === "ES256" || algorithm === "ES384" || algorithm === "ES512") {
240241
return new ECDSA(ecdsaDictionary[algorithm].hash, ecdsaDictionary[algorithm].curve);
241242
}

src/oauth2/index.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { sha256 } from "../crypto/index.js";
22
import { base64, base64url } from "../encoding/index.js";
3-
import { createDate, TimeSpan } from "../index.js";
3+
import { TimeSpan, addToDate } from "../index.js";
44

55
export class OAuth2Client {
66
public clientId: string;
@@ -237,7 +237,7 @@ export class OAuth2TokenRevocationClient {
237237
const retryAfterNumber = parseInt(retryAfterHeader);
238238
if (!Number.isNaN(retryAfterNumber)) {
239239
throw new OAuth2TokenRevocationRetryError({
240-
retryAfter: createDate(new TimeSpan(retryAfterNumber, "s"))
240+
retryAfter: addToDate(new Date(), new TimeSpan(retryAfterNumber, "s"))
241241
});
242242
}
243243
const retryAfterDate = parseDateString(retryAfterHeader);
@@ -303,15 +303,6 @@ export interface TokenResponseBody {
303303
scope?: string;
304304
}
305305

306-
export interface OAuth2Endpoints {
307-
authorizeEndpoint: string;
308-
tokenEndpoint: string;
309-
}
310-
311-
export interface OAuth2EndpointsWithTokenRevocation extends OAuth2Endpoints {
312-
tokenRevocationEndpoint: string;
313-
}
314-
315306
function parseDateString(dateString: string): Date | null {
316307
try {
317308
return new Date(dateString);

src/otp/hotp.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { bigEndian } from "../binary/uint.js";
2-
import { HMAC } from "../crypto/hmac.js";
2+
import { HMAC } from "../crypto/signing-algorithm/hmac.js";
33

44
export async function generateHOTP(
55
key: Uint8Array,

src/time.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
export type TimeSpanUnit = "ms" | "s" | "m" | "h" | "d" | "w";
2+
3+
export class TimeSpan {
4+
constructor(value: number, unit: TimeSpanUnit) {
5+
this.value = value;
6+
this.unit = unit;
7+
}
8+
9+
public value: number;
10+
public unit: TimeSpanUnit;
11+
12+
public milliseconds(): number {
13+
if (this.unit === "ms") {
14+
return this.value;
15+
}
16+
if (this.unit === "s") {
17+
return this.value * 1000;
18+
}
19+
if (this.unit === "m") {
20+
return this.value * 1000 * 60;
21+
}
22+
if (this.unit === "h") {
23+
return this.value * 1000 * 60 * 60;
24+
}
25+
if (this.unit === "d") {
26+
return this.value * 1000 * 60 * 60 * 24;
27+
}
28+
return this.value * 1000 * 60 * 60 * 24 * 7;
29+
}
30+
31+
public seconds(): number {
32+
return this.milliseconds() / 1000;
33+
}
34+
35+
public transform(x: number): TimeSpan {
36+
return new TimeSpan(Math.round(this.milliseconds() * x), "ms");
37+
}
38+
}
39+
40+
export function isWithinExpirationDate(date: Date): boolean {
41+
return Date.now() < date.getTime();
42+
}
43+
44+
export function addToDate(date: Date, timeSpan: TimeSpan): Date {
45+
return new Date(date.getTime() + timeSpan.milliseconds());
46+
}

0 commit comments

Comments
 (0)