Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' of github.com:zsqk/deno-fn
Browse files Browse the repository at this point in the history
# Conflicts:
#	.github/workflows/deno.yml
#	deno/git.test.ts
#	deno/git.ts
#	deno/run.test.ts
#	deno/run.ts
#	js/aes.test.ts
#	js/date.test.ts
#	js/hash.benchmark.ts
#	js/hash.test.ts
#	js/hash.ts
#	js/lz-string.test.ts
#	js/str.test.ts
#	js/ua.test.ts
  • Loading branch information
iugo committed May 30, 2023
2 parents 62335ae + f3737ab commit 0b1a8ce
Show file tree
Hide file tree
Showing 10 changed files with 422 additions and 15 deletions.
33 changes: 33 additions & 0 deletions cli/gen-git-push.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// deno run -A tools/cli.ts
import { parse } from 'https://deno.land/[email protected]/flags/mod.ts';
import { genGitPush } from "../deno/git.ts";

const args = parse<
Partial<
{
"repo-name": string;
"repo-uri": string;
"branch": string;
"ssh": string;
}
>
>(
Deno.args,
);

const repoName = args['repo-name'];
const repoURI = args['repo-uri'];
const branch = args['branch'];
const sshPrivateKey = args.ssh?.replaceAll("\\n", '\n');

if (!repoName || !repoURI || !sshPrivateKey) {
console.error('args invalid')
Deno.exit(1);
}

await genGitPush({
repoName,
repoURI,
branch,
sshPrivateKey,
});
1 change: 1 addition & 0 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"strict": true
},
"lock": false,
"lint": {
"files": {
"include": [
Expand Down
255 changes: 255 additions & 0 deletions js/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
// 结构化的时间到 ms
// 渲染 ms 时间 (通过结构化)

import {
MillisecondTimestamp,
MonthString,
UnixTimestamp,
} from '../ts/time.ts';

/**
* 已被分析并且结构化的时间
*/
Expand Down Expand Up @@ -190,3 +196,252 @@ export function timeSummarize(

return ams;
}

/**
* 获取月份
* @author iugo <[email protected]>
*/
export function getMonths(
/** 开始时间 (包含) */
startAt: UnixTimestamp,
/** 结束时间 (包含) */
endAt: UnixTimestamp,
opt: { timezone?: string } = {},
): {
/** 月份, 202101 */
months: string[];
/** 之前的 不足一个月 */
before?: [UnixTimestamp, UnixTimestamp];
/** 之后的 不足一个月 */
after?: [UnixTimestamp, UnixTimestamp];
} {
if (startAt > endAt) {
throw new Error(`时间段选择有误, 开始时间不该大于结束时间`);
}

const months: string[] = [];
/** 开始时间的毫秒时间戳 */
const startMillisecond = startAt * 1000;
/** 结束时间的毫秒时间戳 */
const endMillisecond = endAt * 1000;
/** 开始 Date */
const start = new Date(startMillisecond);
/** 结束 Date */
const end = new Date(endMillisecond);
/** 开始年份 */
let startYear = start.getFullYear();
/** 结束年份 */
let endYear = end.getFullYear();
/** 开始月份 */
let startMonth = start.getMonth() + 1;
/** 结束月份 */
let endMonth = end.getMonth() + 1;

// 如果在同一个月份, 则直接返回基础数值
if (startYear === endYear && startMonth === endMonth) {
return { months: [], before: [startAt, endAt] };
}

let before: [UnixTimestamp, UnixTimestamp] | undefined = undefined;
if (startMillisecond !== getBeginningOfMonth(start, opt)) {
before = [startAt, Math.trunc(getEndOfMonth(start, opt) / 1000)];
if (startMonth === 12) {
startYear += 1;
startMonth = 1;
} else {
startMonth += 1;
}
}

let after: [UnixTimestamp, UnixTimestamp] | undefined = undefined;
if (endMillisecond !== getEndOfMonth(end, opt)) {
after = [Math.trunc(getBeginningOfMonth(end, opt) / 1000), endAt];
if (endMonth === 1) {
endYear -= 1;
endMonth = 12;
} else {
endMonth -= 1;
}
}

// 如果没有一个完整的月
if (endYear < startYear || (startYear === endYear && endMonth < startMonth)) {
return { months: [], before: [startAt, endAt] };
}

// 特殊情况考虑完毕, 下面开始计算 months

// 如果在同一年, 则只计算月差
if (startYear === endYear) {
for (let m = startMonth; m <= endMonth; m++) {
months.push(`${startYear}${m.toString().padStart(2, '0')}`);
}
} else {
for (let m = startMonth; m <= 12; m++) {
months.push(`${startYear}${m.toString().padStart(2, '0')}`);
}
for (let y = startYear + 1; y < endYear; y++) {
months.push(
`${y}01`,
`${y}02`,
`${y}03`,
`${y}04`,
`${y}05`,
`${y}06`,
`${y}07`,
`${y}08`,
`${y}09`,
`${y}10`,
`${y}11`,
`${y}12`,
);
}
for (let m = 1; m <= endMonth; m++) {
months.push(`${endYear}${m.toString().padStart(2, '0')}`);
}
}

// TODO: 如果不在同一年, 则计算开始与 12 的差, 结束与 1 的差
// TODO: 如果年差超过 1, 则附加 多出来年份的每一月

return { months, before, after };
}

/**
* 获取月末时间
* @param v 支持 Date 和 `202101...` 这样的字符串
* @returns 月末时间的毫秒时间戳
* @author iugo <[email protected]>
*/
export function getEndOfMonth(
v: Date | MonthString,
opt: { timezone?: string } = {},
): MillisecondTimestamp {
let d: Date;
if (v instanceof Date) {
d = v;
} else if (typeof v === 'string') {
let str = `${v.substring(0, 4)}/${v.substring(4, 6)}`;
if (opt.timezone) {
str += ' ' + opt.timezone;
}
d = new Date(str);
} else {
throw new TypeError('无效的参数类型');
}
if (d.toString() === 'Invalid Date') {
throw new Error('无效的时间');
}
const y = d.getFullYear();
const m = d.getMonth() + 1;
let key = m === 12
? `${y + 1}/01`
: `${y}/${(m + 1).toString().padStart(2, '0')}`;
if (opt.timezone) {
key += ' ' + opt.timezone;
}
return new Date(key).getTime() - 1000;
}

/**
* 获取月初时间
* @param v 支持 Date 和 `202101...` 这样的字符串
* @returns 月初时间的毫秒时间戳
* @author iugo <[email protected]>
*/
export function getBeginningOfMonth(
v: Date | MonthString,
opt: { timezone?: string } = {},
): MillisecondTimestamp {
let d: Date;
if (v instanceof Date) {
d = v;
} else if (typeof v === 'string') {
let str = `${v.substring(0, 4)}/${v.substring(4, 6)}`;
if (opt.timezone) {
str += ' ' + opt.timezone;
}
d = new Date(str);
} else {
throw new TypeError('无效的参数类型');
}
if (d.toString() === 'Invalid Date') {
throw new Error('无效的时间');
}
const y = d.getFullYear();
const m = d.getMonth() + 1;
let str = `${y}/${m.toString().padStart(2, '0')}`;
if (opt.timezone) {
str += ' ' + opt.timezone;
}
return new Date(str).getTime();
}

/**
* 获取 UNIX 时间戳
* @param v 毫秒时间戳, Date, 或者生成 Date 所需的字符串
* @returns
*/
export function toUnixTimestamp(
v: MillisecondTimestamp | Date | string = Date.now(),
): UnixTimestamp {
let t: number;
if (typeof v === 'string') {
t = new Date(v).getTime();
} else if (v instanceof Date) {
t = v.getTime();
} else {
t = v;
}
return Math.trunc(t / 1000);
}

/**
* 解析 Date 对象的时间
* @param v 需要解析的时间, 默认为当前
* @param opt 参数
* @returns
*/
export function parseDate(
v:
| Date
| { unixMS: MillisecondTimestamp }
| { unixS: UnixTimestamp } = new Date(),
opt: { isUTC?: boolean } = {},
): {
y: string;
m: string;
d: string;
h: string;
min: string;
s: string;
} {
let date: Date;
if ('unixMS' in v) {
date = new Date(v.unixMS);
} else if ('unixS' in v) {
date = new Date(v.unixS * 1000);
} else {
date = v;
}

if (opt.isUTC) {
const y = date.getUTCFullYear().toString();
const m = (date.getUTCMonth() + 1).toString().padStart(2, '0');
const d = date.getUTCDate().toString().padStart(2, '0');
const h = date.getUTCHours().toString().padStart(2, '0');
const min = date.getUTCMinutes().toString().padStart(2, '0');
const s = date.getUTCSeconds().toString().padStart(2, '0');

return { y, m, d, h, min, s };
}

const y = date.getFullYear().toString();
const m = (date.getMonth() + 1).toString().padStart(2, '0');
const d = date.getDate().toString().padStart(2, '0');
const h = date.getHours().toString().padStart(2, '0');
const min = date.getMinutes().toString().padStart(2, '0');
const s = date.getSeconds().toString().padStart(2, '0');

return { y, m, d, h, min, s };
}
46 changes: 46 additions & 0 deletions js/hash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { encode } from "../lib/hex";
import { decode } from "../lib/base64";

export async function hashString(
algorithm: "SHA-1" | "SHA-256" | "SHA-512",
Expand Down Expand Up @@ -56,3 +57,48 @@ export async function hmac(

return res;
}

/**
* Sign data with RSA
* - only pkcs8
* - only RSASSA-PKCS1-v1_5
* @param key
* @param d
* @returns
*/
export async function rasSign(
key: {
hash: 'SHA-256' | 'SHA-512';
/** secret key */
s: string | Uint8Array;
} | CryptoKey,
/** data */
d: string | Uint8Array,
): Promise<Uint8Array> {
let cryptoKey: CryptoKey;
if (key instanceof CryptoKey) {
cryptoKey = key;
} else {
const { s, hash } = key;
const keyData = typeof s === 'string' ? decode(s) : s;
cryptoKey = await crypto.subtle.importKey(
'pkcs8',
keyData,
{ name: 'RSASSA-PKCS1-v1_5', hash: { name: hash } },
true,
['sign'],
);
}

const data = typeof d === 'string' ? new TextEncoder().encode(d) : d;

const res = new Uint8Array(
await crypto.subtle.sign(
'RSASSA-PKCS1-v1_5',
cryptoKey,
data,
),
);

return res;
}
19 changes: 19 additions & 0 deletions js/ip.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { assert } from 'https://deno.land/[email protected]/testing/asserts.ts';
import { checkIPv4 } from './ip.ts';

Deno.test('ipv4', () => {
// 不允许无效的字符
assert(!checkIPv4(''));

assert(!checkIPv4('a.a.a.a'), '不应该允许出现特殊字符');

assert(!checkIPv4('1.1.1.a'), '不应该允许出现特殊字符');

assert(!checkIPv4('1.1.1. 1'), '不应该允许出现特殊字符');

assert(!checkIPv4('300.1.1.1'), '不应该允许超位');

assert(!checkIPv4('1.1.1.1.1'), '不允许长度超长');

assert(checkIPv4('1.1.1.1'));
});
Loading

0 comments on commit 0b1a8ce

Please sign in to comment.