Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ArrayBuffer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ export namespace ArrayBuffer {
>(array: T): T
export function random(length: number): Uint8Array
export function random(array: ArrayBufferView | number): ArrayBufferView {
return crypto.getRandomValues(typeof array == "number" ? new Uint8Array(length) : array)
return crypto.getRandomValues(typeof array == "number" ? new Uint8Array(array) : array)
}
}
4 changes: 4 additions & 0 deletions Base64/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,8 @@ describe("Base64", () => {
expect(
cryptly.Base64.combine(["V6h7cyBpcyB0taUgZGF0YSAoK72", "Y4y5IGNhcm5hbCBwbGVhc3VyZ7u8"])
).toMatchInlineSnapshot(`"ZJOykrzCrsfCykFfzZKF0JjS4D7z"`))
it("next", () =>
expect(cryptly.Base64.next("V6h7cyBpcyB0taUgZGF0YSAoK7z", 1, "ordered")).toMatchInlineSnapshot(
`"V6h7cyBpcyB0taUgZGF0YSAoK8-"`
))
})
1 change: 0 additions & 1 deletion Base64/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ArrayBuffer } from "../ArrayBuffer"
import { Standard as Base64Standard } from "./Standard"

export type Base64 = string

export namespace Base64 {
export import Standard = Base64Standard
export const type = isly.named<Base64>("cryptly.Base64", isly.string(/^[A-Za-z0-9+/\-_=]*$/))
Expand Down
6 changes: 2 additions & 4 deletions Encrypter/Aes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ export class Aes {
async export(parts?: number | Uint8Array | Uint8Array[] | Base64 | Base64[]): Promise<Base64 | Base64[]> {
let result: Base64 | Base64[]
const key = new Uint8Array(await crypto.subtle.exportKey("raw", await this.key))
if (parts == undefined)
result = (await this.export(1))[0]
if (parts == undefined) result = (await this.export(1))[0]
else if (typeof parts == "number")
result = await this.export(parts > 1 ? Aes.generateRandomKeys(key.length, parts - 1) : [])
else if (Base64.is(parts))
Expand Down Expand Up @@ -97,8 +96,7 @@ export class Aes {
}
private static reduceKeys(keys: Uint8Array[]): Uint8Array {
const result = new Uint8Array(keys[0].length)
for (let index = 0; index < keys[0].length; index++)
result[index] = keys.reduce((p, c) => p ^ c[index], 0)
for (let index = 0; index < keys[0].length; index++) result[index] = keys.reduce((p, c) => p ^ c[index], 0)
return result
}
}
Expand Down
59 changes: 0 additions & 59 deletions Identifier/Identifier16.spec.ts

This file was deleted.

62 changes: 0 additions & 62 deletions Identifier/Identifier64.spec.ts

This file was deleted.

41 changes: 41 additions & 0 deletions Identifier/Length.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { cryptly } from "../index"

describe("Identifier.Length", () => {
it("bytes", () =>
expect(cryptly.Identifier.Length.values.map(cryptly.Identifier.Length.bytes)).toMatchInlineSnapshot(`
[
3,
6,
9,
12,
15,
18,
21,
24,
27,
30,
33,
36,
39,
42,
45,
48,
51,
54,
57,
60,
63,
66,
69,
72,
75,
78,
81,
84,
87,
90,
93,
96,
]
`))
})
3 changes: 3 additions & 0 deletions Identifier/Length.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ export namespace Length {
export const type = isly.named("cryptly.Identifier.Length", isly.number<Length>(values as any as number[]))
export const is = type.is
export const flaw = type.flaw
export function bytes(length: Length): number {
return (length / 4) * 3
}
}
10 changes: 10 additions & 0 deletions Identifier/Standard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { isly } from "isly"

export type Standard = typeof Standard.values[number]

export namespace Standard {
export const values = ["url", "ordered", "reversed"] as const
export const type = isly.named<Standard>("cryptly.Identifier.Standard", isly.string(values))
export const is = type.is
export const flaw = type.flaw
}
110 changes: 48 additions & 62 deletions Identifier/index.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,86 @@
import { isly } from "isly"
import { ArrayBuffer } from "../ArrayBuffer"
import { Base16 } from "../Base16"
import { Base64 } from "../Base64"
import { crypto } from "../crypto"
import { Length as IdentifierLength } from "./Length"
import { Standard as IdentifierStandard } from "./Standard"

export type Identifier = string

export namespace Identifier {
export import Length = IdentifierLength
export import Standard = IdentifierStandard
export const type = isly.named("cryptly.Identifier", isly.string<string>(/^[a-zA-Z0-9\-_]{4,128}$/))
export function is(value: Identifier | any, length?: Length): value is Identifier {
return type.is(value) && (length == undefined || value.length == length)
}
export const flaw = type.flaw
export function convert(identifier: Identifier, length: Length, standard?: Base64.Standard): Identifier
export function convert(identifier: Identifier, from: Base64.Standard, to?: Base64.Standard): Identifier
export function convert(identifier: Identifier, length: Length, standard?: Identifier.Standard): Identifier
export function convert(identifier: Identifier, from: Identifier.Standard, to?: Identifier.Standard): Identifier
export function convert(
identifier: Identifier,
length: Base64.Standard | Length,
standard: Base64.Standard = "url"
length: Identifier.Standard | Length,
standard: Identifier.Standard = "url"
): Identifier {
return Base64.Standard.is(length)
return Identifier.Standard.is(length)
? Base64.convert(identifier, length, standard)
: identifier.length < length
? min(length).slice(0, length - identifier.length) + identifier
? min(length, standard).slice(0, length - identifier.length) + identifier
: identifier.length > length
? identifier.slice(identifier.length - length)
: identifier
}
export function fromUint24(value: number): Identifier {
return fromHexadecimal(value.toString(16).padStart(6, "0"))
export function fromBase16(value: Base16, standard: Identifier.Standard = "url"): Identifier {
return fromBinary(Base16.decode(value), standard)
}
export function toUint24(identifier: Identifier): number {
return Number.parseInt(toHexadecimal(identifier, 6), 16)
export function toBase16(identifier: Identifier, standard: Identifier.Standard = "url"): Base16 {
return Base16.encode(Base64.decode(identifier, standard))
}
export function fromUint48(value: number): Identifier {
return fromHexadecimal(value.toString(16).padStart(12, "0"))
export function fromUint24(value: number, standard: Identifier.Standard = "url"): Identifier {
return fromBase16(value.toString(16).padStart(6, "0"), standard)
}
export function toUint48(identifier: Identifier): number {
return Number.parseInt(toHexadecimal(identifier, 12), 16)
export function toUint24(identifier: Identifier, standard: Identifier.Standard = "url"): number {
return Number.parseInt(toBase16(identifier, standard).slice(0, 6), 16)
}
export function fromBinary(identifier: Uint8Array, standard: Base64.Standard = "url"): Identifier {
export function fromUint48(value: number, standard: Identifier.Standard = "url"): Identifier {
return fromBase16(value.toString(16).padStart(12, "0"), standard)
}
export function toUint48(identifier: Identifier, standard: Identifier.Standard = "url"): number {
return Number.parseInt(toBase16(identifier, standard).slice(0, 12), 16)
}
export function fromBinary(identifier: Uint8Array, standard: Identifier.Standard = "url"): Identifier {
return Base64.encode(identifier, standard)
}
export function toBinary(identifier: Identifier): Uint8Array {
return Base64.decode(identifier, "url")
export function toBinary(identifier: Identifier, standard: Identifier.Standard = "url"): Uint8Array {
return Base64.decode(identifier, standard)
}
export function generate(length: Length): Identifier
export function generate(
length: Length,
ordering: Extract<Base64.Standard, "ordered" | "reversed">,
value: number | Uint8Array | string
): Identifier
export function generate(
length: Length,
ordering?: Extract<Base64.Standard, "ordered" | "reversed">,
value?: number | Uint8Array | string
standard: Identifier.Standard = "url",
prefix?: Base64 | Uint8Array | number | bigint
): Identifier {
let result: Identifier | undefined = undefined
if (value || value == 0 || value == "")
result = Base64.encode(value, ordering).substring(0, length)
return (
(result ?? "") +
fromBinary(crypto.getRandomValues(new Uint8Array((length / 4) * 3)), ordering).substring(
0,
length - (result ? result.length : 0)
)
)
}
export function fromHexadecimal(identifier: string): Identifier {
if (identifier.length % 2 == 1)
identifier += "0"
const result = new Uint8Array(identifier.length / 2)
for (let index = 0; index < result.length; index++)
result[index] = Number.parseInt(identifier[index * 2], 16) * 16 + Number.parseInt(identifier[index * 2 + 1], 16)
return fromBinary(result)
}
export function toHexadecimal(identifier: Identifier, length?: number): string {
const data = Base64.decode(identifier, "url")
let result: string[] = []
for (const d of data)
result.push(Math.floor(d / 16).toString(16), (d % 16).toString(16))
if (length)
result = result.slice(0, length)
return result.join("")
return !prefix
? Base64.encode(ArrayBuffer.random(Identifier.Length.bytes(length)), standard)
: prefix instanceof Uint8Array || typeof prefix == "number" || typeof prefix == "bigint"
? generate(length, standard, Base64.encode(prefix, standard))
: prefix.length < length
? prefix + generate(length, standard).slice(prefix.length)
: prefix.length > length
? prefix.slice(0, length)
: prefix
}
export function min(length: Length): Identifier {
return "".padStart(length, "-")
export function min(length: Length, standard: Identifier.Standard = "url"): Identifier {
const result = "".padStart(length, "-")
return standard != "ordered" ? convert(result, "ordered", standard) : result
}
export function max(length: Length): Identifier {
return "".padStart(length, "z")
export function max(length: Length, standard: Identifier.Standard = "url"): Identifier {
const result = "".padStart(length, "z")
return standard != "ordered" ? convert(result, "ordered", standard) : result
}
export function next(identifier: Identifier, increment = 1): Identifier {
const result = Base64.next(identifier, increment, "ordered")
return result.length == identifier.length ? result : result.substring(result.length - identifier.length)
export function next(identifier: Identifier, standard: Identifier.Standard = "url", increment = 1): Identifier {
return convert(Base64.next(identifier, increment, standard), Length.type.get(identifier) ?? 128, standard)
}
export function previous(identifier: Identifier, decrement = 1): Identifier {
return next(identifier, -decrement)
export function previous(identifier: Identifier, standard: Identifier.Standard = "url", decrement = 1): Identifier {
return next(identifier, standard, -decrement)
}
}
Loading