Skip to content

Commit

Permalink
clean up. (#103)
Browse files Browse the repository at this point in the history
* clean up.

* eckey.

* change name.

* purge.

* fix dataurl

* remove type.
  • Loading branch information
dojyorin committed May 24, 2024
1 parent aebbb5c commit 09b2014
Show file tree
Hide file tree
Showing 19 changed files with 122 additions and 245 deletions.
6 changes: 3 additions & 3 deletions deps.deno_ext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export {Logger, ConsoleHandler, FileHandler} from "https://deno.land/std@0.223.0/log/mod.ts";
export {format} from "https://deno.land/std@0.223.0/datetime/mod.ts";
export {Logger, ConsoleHandler, FileHandler} from "https://deno.land/std@0.224.0/log/mod.ts";
export {format} from "https://deno.land/std@0.224.0/datetime/mod.ts";

export {type Element, DOMParser} from "https://deno.land/x/[email protected]/deno-dom-wasm.ts";

// @deno-types="npm:@types/[email protected].14"
// @deno-types="npm:@types/[email protected].15"
export {createTransport} from "npm:[email protected]";
8 changes: 4 additions & 4 deletions deps.pure_ext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @deno-types="https://deno.land/std@0.223.0/csv/mod.ts"
export {parse, stringify} from "https://esm.sh/gh/denoland/deno_std@0.223.0/csv/mod.ts?bundle&target=esnext";
// @deno-types="https://deno.land/x/[email protected].43/index.d.ts"
export {ZipReader, ZipWriter, Uint8ArrayReader, Uint8ArrayWriter} from "https://esm.sh/gh/gildas-lormeau/[email protected].43/index.js?bundle&target=esnext";
// @deno-types="https://deno.land/std@0.224.0/csv/mod.ts"
export {parse, stringify} from "https://esm.sh/gh/denoland/deno_std@0.224.0/csv/mod.ts?bundle&target=esnext";
// @deno-types="https://deno.land/x/[email protected].44/index.d.ts"
export {ZipReader, ZipWriter, Uint8ArrayReader, Uint8ArrayWriter} from "https://esm.sh/gh/gildas-lormeau/[email protected].44/index.js?bundle&target=esnext";

// @deno-types="https://cdn.sheetjs.com/xlsx-0.20.2/package/types/index.d.ts"
export {type WorkBook as RawWorkBook, type WorkSheet as RawWorkSheet, type CellObject as RawWorkCell, set_cptable, read as xlsxRead, write as xlsxWrite, utils as xlsxUtil} from "https://cdn.sheetjs.com/xlsx-0.20.2/package/xlsx.mjs";
Expand Down
8 changes: 4 additions & 4 deletions deps.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export {assertEquals} from "https://deno.land/std@0.223.0/assert/mod.ts";
export {dirname, fromFileUrl} from "https://deno.land/std@0.223.0/path/mod.ts";
export {exists} from "https://deno.land/std@0.223.0/fs/mod.ts";
export {delay} from "https://deno.land/std@0.223.0/async/mod.ts";
export {assertEquals} from "https://deno.land/std@0.224.0/assert/mod.ts";
export {dirname, fromFileUrl} from "https://deno.land/std@0.224.0/path/mod.ts";
export {exists} from "https://deno.land/std@0.224.0/fs/mod.ts";
export {delay} from "https://deno.land/std@0.224.0/async/mod.ts";

export {DOMParser} from "https://deno.land/x/[email protected]/deno-dom-wasm.ts";

Expand Down
8 changes: 4 additions & 4 deletions src/deno_ext/smtp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {type DataMap} from "../pure/minipack.ts";
/**
* E-MAIL message.
*/
export interface MailMessage{
export interface MailMessage {
from: string;
to: string[];
title: string;
Expand Down Expand Up @@ -36,7 +36,7 @@ export async function smtpSend(path:string, message:MailMessage):Promise<void>{

const smtp = createTransport({
host: hostname,
port: Number(port),
port: parseInt(port),
secure: protocol === "smtps:",
auth: username ? {
user: decodeURIComponent(username),
Expand All @@ -48,10 +48,10 @@ export async function smtpSend(path:string, message:MailMessage):Promise<void>{
from: message.from,
to: message.to,
cc: message.cc,
attachments: message.files?.map(({name, body}) => ({filename: name, content: body})),
bcc: message.bcc,
subject: message.title,
text: message.body
text: message.body,
attachments: <typeof smtp.options.attachments>message.files?.map(({name, body}) => ({filename: name, content: body}))
});

smtp.close();
Expand Down
17 changes: 2 additions & 15 deletions src/pure/base64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,7 @@
* ```
*/
export function base64Encode(data:Uint8Array):string{
return btoa([...data].map(v => String.fromCharCode(v)).join(""));
}

/**
* Convert from binary to base64 encoded DataURL.
* Default MIME type is `application/octet-stream`.
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const data = base64EncodeDataURL(bin);
* ```
*/
export function base64EncodeDataURL(data:Uint8Array, type?:string):string{
return `data:${type ?? "application/octet-stream"};base64,${base64Encode(data)}`;
return btoa(Array.from(data, v => String.fromCharCode(v)).join(""));
}

/**
Expand All @@ -34,5 +21,5 @@ export function base64EncodeDataURL(data:Uint8Array, type?:string):string{
* ```
*/
export function base64Decode(data:string):Uint8Array{
return new Uint8Array([...atob(data)].map(v => v.charCodeAt(0)));
return new Uint8Array(Array.from(atob(data), v => v.charCodeAt(0)));
}
122 changes: 51 additions & 71 deletions src/pure/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,36 @@
import {byteConcat} from "./byte.ts";

/**
* Serialized `CryptoKeyPair`.
*/
export type PortableCryptoKeyPair = Record<keyof CryptoKeyPair, Uint8Array>;
interface PubKey {
pub: Uint8Array;
key: Uint8Array;
}

const AES_MODE = "AES-GCM";
const AES_BIT = 128;
const FORMAT_PUB = "spki";
const FORMAT_PRI = "pkcs8";

const CURVE_ECDH = Object.freeze<EcKeyAlgorithm>({
const AES_SIZE = 128;
const CURVE_KEX = Object.freeze<EcKeyAlgorithm>({
name: "ECDH",
namedCurve: "P-256"
});

const CURVE_ECDSA = Object.freeze<EcKeyAlgorithm>({
name: "ECDSA",
namedCurve: "P-256"
});

const MAC_ECDSA = Object.freeze<EcdsaParams>({
const CURVE_DSA = Object.freeze<EcKeyAlgorithm & EcdsaParams>({
name: "ECDSA",
namedCurve: "P-256",
hash: "SHA-256"
});

async function generateKey(alg:EcKeyAlgorithm, usage:KeyUsage[]){
const {publicKey, privateKey} = await crypto.subtle.generateKey(alg, true, usage);

return {
publicKey: new Uint8Array(await crypto.subtle.exportKey(FORMAT_PUB, publicKey)),
privateKey: new Uint8Array(await crypto.subtle.exportKey(FORMAT_PRI, privateKey))
return <PubKey>{
pub: new Uint8Array(await crypto.subtle.exportKey("spki", publicKey)),
key: new Uint8Array(await crypto.subtle.exportKey("pkcs8", privateKey))
};
}

async function deriveKey({publicKey, privateKey}:PortableCryptoKeyPair){
async function deriveKey(pub:Uint8Array, key:Uint8Array){
return await crypto.subtle.deriveKey({
name: CURVE_ECDH.name,
public: await crypto.subtle.importKey(FORMAT_PUB, publicKey, CURVE_ECDH, false, [])
}, await crypto.subtle.importKey(FORMAT_PRI, privateKey, CURVE_ECDH, false, ["deriveKey"]), {
name: CURVE_KEX.name,
public: await crypto.subtle.importKey("spki", pub, CURVE_KEX, false, [])
}, await crypto.subtle.importKey("pkcs8", key, CURVE_KEX, false, ["deriveKey"]), {
name: AES_MODE,
length: AES_BIT
length: AES_SIZE
}, false, ["encrypt", "decrypt"]);
}

Expand All @@ -56,41 +46,43 @@ export function cryptoRandom(n:number):Uint8Array{
}

/**
* Derive SHA2 hash value from binary.
* Derive hash value from binary.
* Default is SHA-256.
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const hash = await cryptoHash(bin);
* ```
*/
export async function cryptoHash(data:Uint8Array, sha?:`SHA-${256 | 384 | 512}`):Promise<Uint8Array>{
return new Uint8Array(await crypto.subtle.digest(sha ?? "SHA-256", data));
export async function cryptoHash(data:Uint8Array, alg?:string):Promise<Uint8Array>{
return new Uint8Array(await crypto.subtle.digest(alg ?? "SHA-256", data));
}

/**
* Generate exportable public-key pair for ECDH.
* Curve algorithm is "NIST P-256".
* Key format is SPKI for public-key and PKCS8 for private-key.
* @example
* ```ts
* const k1 = await cryptoGenerateEncryptKey();
* const k2 = await cryptoGenerateEncryptKey();
* const key1 = await cryptoGenerateEncryptKey();
* const key2 = await cryptoGenerateEncryptKey();
* ```
*/
export async function cryptoGenerateEncryptKey():Promise<PortableCryptoKeyPair>{
return await generateKey(CURVE_ECDH, ["deriveKey"]);
export async function cryptoGenerateEncryptKey():Promise<PubKey>{
return await generateKey(CURVE_KEX, ["deriveKey"]);
}

/**
* Generate exportable public-key pair for ECDSA.
* Curve algorithm is "NIST P-256".
* Key format is SPKI for public-key and PKCS8 for private-key.
* @example
* ```ts
* const {publicKey, privateKey} = await cryptoGenerateSignKey();
* const {pub, key} = await cryptoGenerateSignKey();
* ```
*/
export async function cryptoGenerateSignKey():Promise<PortableCryptoKeyPair>{
return await generateKey(CURVE_ECDSA, ["sign", "verify"]);
export async function cryptoGenerateSignKey():Promise<PubKey>{
return await generateKey(CURVE_DSA, ["sign", "verify"]);
}

/**
Expand All @@ -100,25 +92,19 @@ export async function cryptoGenerateSignKey():Promise<PortableCryptoKeyPair>{
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const k1 = await cryptoGenerateEncryptKey();
* const k2 = await cryptoGenerateEncryptKey();
* const cipher = await cryptoEncrypt(bin, {
* publicKey: k1.publicKey,
* privateKey: k2.privateKey
* });
* const decrypt = await cryptoDecrypt(cipher, {
* publicKey: k2.publicKey,
* privateKey: k1.privateKey
* });
* const key1 = await cryptoGenerateEncryptKey();
* const key2 = await cryptoGenerateEncryptKey();
* const encrypt = await cryptoEncrypt(bin, key1.pub, key2.key);
* const decrypt = await cryptoDecrypt(encrypt, key2.pub, key1.key);
* ```
*/
export async function cryptoEncrypt(data:Uint8Array, {publicKey, privateKey}:PortableCryptoKeyPair):Promise<Uint8Array>{
const aes = {
export async function cryptoEncrypt(data:Uint8Array, pub:Uint8Array, key:Uint8Array):Promise<Uint8Array>{
const aes = <AesGcmParams>{
name: AES_MODE,
iv: cryptoRandom(12)
};

return byteConcat(aes.iv, await crypto.subtle.encrypt(aes, await deriveKey({publicKey, privateKey}), data));
return new Uint8Array(await new Blob([aes.iv, await crypto.subtle.encrypt(aes, await deriveKey(pub, key), data)]).arrayBuffer());
}

/**
Expand All @@ -128,51 +114,45 @@ export async function cryptoEncrypt(data:Uint8Array, {publicKey, privateKey}:Por
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const k1 = await cryptoGenerateEncryptKey();
* const k2 = await cryptoGenerateEncryptKey();
* const cipher = await cryptoEncrypt(bin, {
* publicKey: k1.publicKey,
* privateKey: k2.privateKey
* });
* const decrypt = await cryptoDecrypt(cipher, {
* publicKey: k2.publicKey,
* privateKey: k1.privateKey
* });
* const key1 = await cryptoGenerateEncryptKey();
* const key2 = await cryptoGenerateEncryptKey();
* const encrypt = await cryptoEncrypt(bin, key1.pub, key2.key);
* const decrypt = await cryptoDecrypt(encrypt, key2.pub, key1.key);
* ```
*/
export async function cryptoDecrypt(data:Uint8Array, {publicKey, privateKey}:PortableCryptoKeyPair):Promise<Uint8Array>{
const aes = {
export async function cryptoDecrypt(data:Uint8Array, pub:Uint8Array, key:Uint8Array):Promise<Uint8Array>{
const aes = <AesGcmParams>{
name: AES_MODE,
iv: data.subarray(0, 12)
};

return new Uint8Array(await crypto.subtle.decrypt(aes, await deriveKey({publicKey, privateKey}), data.subarray(aes.iv.byteLength)));
return new Uint8Array(await crypto.subtle.decrypt(aes, await deriveKey(pub, key), data.subarray(aes.iv.byteLength)));
}

/**
* Create signature using private-key.
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const {publicKey, privateKey} = await cryptoGenerateSignKey();
* const sign = await cryptoSign(bin, privateKey);
* const verify = await cryptoVerify(bin, publicKey, sign);
* const {pub, key} = await cryptoGenerateSignKey();
* const sign = await cryptoSign(bin, key);
* const verify = await cryptoVerify(bin, pub, sign);
* ```
*/
export async function cryptoSign(data:Uint8Array, key:Uint8Array):Promise<Uint8Array>{
return new Uint8Array(await crypto.subtle.sign(MAC_ECDSA, await crypto.subtle.importKey(FORMAT_PRI, key, CURVE_ECDSA, false, ["sign"]), data));
return new Uint8Array(await crypto.subtle.sign(CURVE_DSA, await crypto.subtle.importKey("pkcs8", key, CURVE_DSA, false, ["sign"]), data));
}

/**
* Verify signature using public-key.
* @example
* ```ts
* const bin = await Deno.readFile("./file");
* const {publicKey, privateKey} = await cryptoGenerateSignKey();
* const sign = await cryptoSign(bin, privateKey);
* const verify = await cryptoVerify(bin, publicKey, sign);
* const {pub, key} = await cryptoGenerateSignKey();
* const sign = await cryptoSign(bin, key);
* const verify = await cryptoVerify(bin, pub, sign);
* ```
*/
export async function cryptoVerify(data:Uint8Array, key:Uint8Array, sign:Uint8Array):Promise<boolean>{
return await crypto.subtle.verify(MAC_ECDSA, await crypto.subtle.importKey(FORMAT_PUB, key, CURVE_ECDSA, false, ["verify"]), sign, data);
export async function cryptoVerify(data:Uint8Array, pub:Uint8Array, sign:Uint8Array):Promise<boolean>{
return await crypto.subtle.verify(CURVE_DSA, await crypto.subtle.importKey("spki", pub, CURVE_DSA, false, ["verify"]), sign, data);
}
8 changes: 3 additions & 5 deletions src/pure/deflate.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {streamEncode, streamDecode} from "./stream.ts";

type CompressCodec = "gzip" | "deflate" | "deflate-raw";

const COMPRESS_CODEC:CompressCodec = "deflate-raw";
const COMPRESS_CODEC = "deflate-raw";

/**
* Compress binary with DEFLATE format.
Expand All @@ -14,7 +12,7 @@ const COMPRESS_CODEC:CompressCodec = "deflate-raw";
* const decode = await deflateDecode(encode);
* ```
*/
export async function deflateEncode(data:Uint8Array, codec?:CompressCodec):Promise<Uint8Array>{
export async function deflateEncode(data:Uint8Array, codec?:string):Promise<Uint8Array>{
return await streamDecode(streamEncode(data).pipeThrough(new CompressionStream(codec ?? COMPRESS_CODEC)));
}

Expand All @@ -28,6 +26,6 @@ export async function deflateEncode(data:Uint8Array, codec?:CompressCodec):Promi
* const decode = await deflateDecode(encode);
* ```
*/
export async function deflateDecode(data:Uint8Array, codec?:CompressCodec):Promise<Uint8Array>{
export async function deflateDecode(data:Uint8Array, codec?:string):Promise<Uint8Array>{
return await streamDecode(streamEncode(data).pipeThrough(new DecompressionStream(codec ?? COMPRESS_CODEC)));
}
4 changes: 2 additions & 2 deletions src/pure/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {base64Encode} from "./base64.ts";

interface ResponseType{
interface ResponseType {
"text": string;
"base64": string;
"json": unknown;
Expand All @@ -18,7 +18,7 @@ interface ResponseType{
/**
* Added `query` which allows you to specify query string to `RequestInit`.
*/
export interface FetchInit extends Omit<RequestInit, "integrity" | "window">{
export interface FetchInit extends Omit<RequestInit, "integrity" | "window"> {
signal?: AbortSignal;
headers?: Headers;
body?: BodyInit;
Expand Down
Loading

0 comments on commit 09b2014

Please sign in to comment.