Skip to content

Commit

Permalink
reorganize project
Browse files Browse the repository at this point in the history
  • Loading branch information
pilcrowonpaper committed Apr 26, 2024
1 parent 5490b32 commit 55e3961
Show file tree
Hide file tree
Showing 20 changed files with 141 additions and 123 deletions.
27 changes: 27 additions & 0 deletions docs/pages/reference/main/addToDate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: "addToDate()"
---

# `addToDate()`

Creates a new `Date` by adding the provided time-span to the one provided. Supports negative time spans.

## Definition

```ts
//$ TimeSpan=/reference/main/TimeSpan
function createDate(date: Date, timeSpan: $$TimeSpan): Date;
```

### Parameters

- `date`
- `timeSpan`

## Example

```ts
import { addToDate, TimeSpan } from "oslo";

const tomorrow = addToDate(new Date(), new TimeSpan(1, "d"));
```
26 changes: 0 additions & 26 deletions docs/pages/reference/main/createDate.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/pages/reference/main/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Provides basic utilities used by other modules.

## Functions

- [`createDate()`](/reference/main/createDate)
- [`addToDate()`](/reference/main/addToDate)
- [`isWithinExpirationDate()`](/reference/main/isWithinExpirationDate)

## Classes
Expand Down
12 changes: 12 additions & 0 deletions src/crypto/bytes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect, test } from "vitest";
import { constantTimeEqual } from "./bytes.js";

test("compareBytes()", () => {
const randomBytes = new Uint8Array(32);
crypto.getRandomValues(randomBytes);
expect(constantTimeEqual(randomBytes, randomBytes)).toBe(true);
const anotherRandomBytes = new Uint8Array(32);
crypto.getRandomValues(anotherRandomBytes);
expect(constantTimeEqual(randomBytes, anotherRandomBytes)).toBe(false);
expect(constantTimeEqual(new Uint8Array(0), new Uint8Array(1))).toBe(false);
});
10 changes: 10 additions & 0 deletions src/crypto/bytes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
if (a.length !== b.length) {
return false;
}
let c = 0;
for (let i = 0; i < a.length; i++) {
c |= a[i]! ^ b[i]!;
}
return c === 0;
}
23 changes: 3 additions & 20 deletions src/crypto/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export { ECDSA } from "./ecdsa.js";
export { HMAC } from "./hmac.js";
export { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";
export { ECDSA, HMAC, RSASSAPKCS1v1_5, RSASSAPSS } from "./signing-algorithm/index.js";
export { sha1, sha256, sha384, sha512 } from "./sha/index.js";
export {
random,
Expand All @@ -9,21 +7,6 @@ export {
alphabet,
generateRandomBoolean
} from "./random.js";
export { constantTimeEqual } from "./bytes.js";

export type { ECDSACurve } from "./ecdsa.js";

export interface KeyPair {
publicKey: Uint8Array;
privateKey: Uint8Array;
}

export function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
if (a.length !== b.length) {
return false;
}
let c = 0;
for (let i = 0; i < a.length; i++) {
c |= a[i]! ^ b[i]!;
}
return c === 0;
}
export type { SigningAlgorithm, KeyPair, ECDSACurve } from "./signing-algorithm/index.js";
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, test, expect } from "vitest";
import { ECDSA } from "./index.js";
import { ECDSA } from "../index.js";

import type { ECDSACurve } from "./ecdsa.js";
import type { SHAHash } from "./sha/index.js";
import type { SHAHash } from "../sha/index.js";

interface TestCase {
hash: SHAHash;
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/ecdsa.ts → src/crypto/signing-algorithm/ecdsa.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { KeyPair } from "./index.js";
import type { SHAHash } from "./sha/index.js";
import type { SHAHash } from "../sha/index.js";
import type { SigningAlgorithm, KeyPair } from "./shared.js";

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

export class ECDSA {
export class ECDSA implements SigningAlgorithm {
private hash: SHAHash;
private curve: ECDSACurve;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, test, expect } from "vitest";
import { HMAC } from "./index.js";
import { HMAC } from "../index.js";

import type { SHAHash } from "./sha/index.js";
import type { SHAHash } from "../sha/index.js";

interface TestCase {
hash: SHAHash;
Expand Down
5 changes: 3 additions & 2 deletions src/crypto/hmac.ts → src/crypto/signing-algorithm/hmac.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SHAHash } from "./sha/index.js";
import type { SigningAlgorithm } from "./shared.js";
import type { SHAHash } from "../sha/index.js";

export class HMAC {
export class HMAC implements SigningAlgorithm {
private hash: SHAHash;
constructor(hash: SHAHash) {
this.hash = hash;
Expand Down
7 changes: 7 additions & 0 deletions src/crypto/signing-algorithm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { ECDSA } from "./ecdsa.js";
export { HMAC } from "./hmac.js";
export { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";

export type { ECDSACurve } from "./ecdsa.js";

export type { SigningAlgorithm, KeyPair } from "./shared.js";
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, test, expect } from "vitest";
import { RSASSAPKCS1v1_5, RSASSAPSS } from "./rsa.js";

import type { SHAHash } from "./sha/index.js";
import type { SHAHash } from "../sha/index.js";

interface TestCase {
hash: SHAHash;
Expand Down
10 changes: 5 additions & 5 deletions src/crypto/rsa.ts → src/crypto/signing-algorithm/rsa.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { KeyPair } from "./index.js";
import type { SHAHash } from "./sha/index.js";
import type { KeyPair, SigningAlgorithm } from "./shared.js";
import type { SHAHash } from "../sha/index.js";

export class RSASSAPKCS1v1_5 {
export class RSASSAPKCS1v1_5 implements SigningAlgorithm {
private hash: SHAHash;
constructor(hash: SHAHash) {
this.hash = hash;
Expand Down Expand Up @@ -132,12 +132,12 @@ export class RSASSAPSS {
return signature;
}

public async generateKeyPair(modulusLength?: 2048 | 4096): Promise<KeyPair> {
public async generateKeyPair(options?: { modulusLength?: 2048 | 4096 }): Promise<KeyPair> {
const cryptoKeyPair = await crypto.subtle.generateKey(
{
name: "RSA-PSS",
hash: this.hash,
modulusLength: modulusLength ?? 2048,
modulusLength: options?.modulusLength ?? 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
},
true,
Expand Down
9 changes: 9 additions & 0 deletions src/crypto/signing-algorithm/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface SigningAlgorithm {
sign(key: Uint8Array, data: Uint8Array): Promise<Uint8Array>;
verify(key: Uint8Array, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
}

export interface KeyPair {
publicKey: Uint8Array;
privateKey: Uint8Array;
}
47 changes: 2 additions & 45 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,3 @@
export type TimeSpanUnit = "ms" | "s" | "m" | "h" | "d" | "w";
export { TimeSpan, isWithinExpirationDate, addToDate } from "./time.js";

export class TimeSpan {
constructor(value: number, unit: TimeSpanUnit) {
this.value = value;
this.unit = unit;
}

public value: number;
public unit: TimeSpanUnit;

public milliseconds(): number {
if (this.unit === "ms") {
return this.value;
}
if (this.unit === "s") {
return this.value * 1000;
}
if (this.unit === "m") {
return this.value * 1000 * 60;
}
if (this.unit === "h") {
return this.value * 1000 * 60 * 60;
}
if (this.unit === "d") {
return this.value * 1000 * 60 * 60 * 24;
}
return this.value * 1000 * 60 * 60 * 24 * 7;
}

public seconds(): number {
return this.milliseconds() / 1000;
}

public transform(x: number): TimeSpan {
return new TimeSpan(Math.round(this.milliseconds() * x), "ms");
}
}

export function isWithinExpirationDate(date: Date): boolean {
return Date.now() < date.getTime();
}

export function createDate(timeSpan: TimeSpan): Date {
return new Date(Date.now() + timeSpan.milliseconds());
}
export type { TimeSpanUnit } from "./time.js";
6 changes: 3 additions & 3 deletions src/jwt/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { describe, test, expect } from "vitest";
import { createJWT, parseJWT, validateJWT } from "./index.js";

import { HMAC } from "../crypto/hmac.js";
import { ECDSA } from "../crypto/ecdsa.js";
import { RSASSAPKCS1v1_5, RSASSAPSS } from "../crypto/rsa.js";
import { HMAC } from "../crypto/signing-algorithm/hmac.js";
import { ECDSA } from "../crypto/signing-algorithm/ecdsa.js";
import { RSASSAPKCS1v1_5, RSASSAPSS } from "../crypto/signing-algorithm/rsa.js";
import { TimeSpan } from "../index.js";

test.each(["ES256", "ES384", "ES512"] as const)(
Expand Down
3 changes: 2 additions & 1 deletion src/jwt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { base64url } from "../encoding/index.js";
import { isWithinExpirationDate } from "../index.js";

import type { TimeSpan } from "../index.js";
import type { SigningAlgorithm } from "../crypto/index.js";

export type JWTAlgorithm =
| "HS256"
Expand Down Expand Up @@ -235,7 +236,7 @@ export interface JWT extends JWTProperties {
parts: [header: string, payload: string, signature: string];
}

function getAlgorithm(algorithm: JWTAlgorithm): ECDSA | HMAC | RSASSAPKCS1v1_5 | RSASSAPSS {
function getAlgorithm(algorithm: JWTAlgorithm): SigningAlgorithm {
if (algorithm === "ES256" || algorithm === "ES384" || algorithm === "ES512") {
return new ECDSA(ecdsaDictionary[algorithm].hash, ecdsaDictionary[algorithm].curve);
}
Expand Down
13 changes: 2 additions & 11 deletions src/oauth2/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { sha256 } from "../crypto/index.js";
import { base64, base64url } from "../encoding/index.js";
import { createDate, TimeSpan } from "../index.js";
import { TimeSpan, addToDate } from "../index.js";

export class OAuth2Client {
public clientId: string;
Expand Down Expand Up @@ -237,7 +237,7 @@ export class OAuth2TokenRevocationClient {
const retryAfterNumber = parseInt(retryAfterHeader);
if (!Number.isNaN(retryAfterNumber)) {
throw new OAuth2TokenRevocationRetryError({
retryAfter: createDate(new TimeSpan(retryAfterNumber, "s"))
retryAfter: addToDate(new Date(), new TimeSpan(retryAfterNumber, "s"))
});
}
const retryAfterDate = parseDateString(retryAfterHeader);
Expand Down Expand Up @@ -303,15 +303,6 @@ export interface TokenResponseBody {
scope?: string;
}

export interface OAuth2Endpoints {
authorizeEndpoint: string;
tokenEndpoint: string;
}

export interface OAuth2EndpointsWithTokenRevocation extends OAuth2Endpoints {
tokenRevocationEndpoint: string;
}

function parseDateString(dateString: string): Date | null {
try {
return new Date(dateString);
Expand Down
2 changes: 1 addition & 1 deletion src/otp/hotp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { bigEndian } from "../binary/uint.js";
import { HMAC } from "../crypto/hmac.js";
import { HMAC } from "../crypto/signing-algorithm/hmac.js";

export async function generateHOTP(
key: Uint8Array,
Expand Down
46 changes: 46 additions & 0 deletions src/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export type TimeSpanUnit = "ms" | "s" | "m" | "h" | "d" | "w";

export class TimeSpan {
constructor(value: number, unit: TimeSpanUnit) {
this.value = value;
this.unit = unit;
}

public value: number;
public unit: TimeSpanUnit;

public milliseconds(): number {
if (this.unit === "ms") {
return this.value;
}
if (this.unit === "s") {
return this.value * 1000;
}
if (this.unit === "m") {
return this.value * 1000 * 60;
}
if (this.unit === "h") {
return this.value * 1000 * 60 * 60;
}
if (this.unit === "d") {
return this.value * 1000 * 60 * 60 * 24;
}
return this.value * 1000 * 60 * 60 * 24 * 7;
}

public seconds(): number {
return this.milliseconds() / 1000;
}

public transform(x: number): TimeSpan {
return new TimeSpan(Math.round(this.milliseconds() * x), "ms");
}
}

export function isWithinExpirationDate(date: Date): boolean {
return Date.now() < date.getTime();
}

export function addToDate(date: Date, timeSpan: TimeSpan): Date {
return new Date(date.getTime() + timeSpan.milliseconds());
}

0 comments on commit 55e3961

Please sign in to comment.