feat: New utils of createOrUpdateVault

This commit is contained in:
BluJ
2023-05-04 15:59:25 -06:00
parent 50bcad0300
commit 22042d7e96
4 changed files with 146 additions and 9 deletions

View File

@@ -208,15 +208,13 @@ export type UniqueBy =
| {
all: readonly UniqueBy[] | UniqueBy[]
}
export type DefaultString =
| string
| {
charset: string
len: number
}
export type DefaultString = string | RandomString
export type RandomString = {
charset: string
len: number
}
// sometimes the type checker needs just a little bit of help
export function isValueSpecListOf<S extends ListValueSpecType>(
function isValueSpecListOf<S extends ListValueSpecType>(
t: ValueSpec,
s: S,
): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } {

View File

@@ -59,3 +59,5 @@ export const smtpConfig = Value.filteredUnion(async ({ effects, utils }) => {
},
}),
)
export const password =

View File

@@ -0,0 +1,112 @@
import { DefaultString } from "../config/configTypes"
export function getDefaultString(defaultSpec: DefaultString): string {
if (typeof defaultSpec === "string") {
return defaultSpec
} else {
let s = ""
for (let i = 0; i < defaultSpec.len; i++) {
s = s + getRandomCharInSet(defaultSpec.charset)
}
return s
}
}
// a,g,h,A-Z,,,,-
export function getRandomCharInSet(charset: string): string {
const set = stringToCharSet(charset)
let charIdx = Math.floor(Math.random() * set.len)
for (let range of set.ranges) {
if (range.len > charIdx) {
return String.fromCharCode(range.start.charCodeAt(0) + charIdx)
}
charIdx -= range.len
}
throw new Error("unreachable")
}
function stringToCharSet(charset: string): CharSet {
let set: CharSet = { ranges: [], len: 0 }
let start: string | null = null
let end: string | null = null
let in_range = false
for (let char of charset) {
switch (char) {
case ",":
if (start !== null && end !== null) {
if (start!.charCodeAt(0) > end!.charCodeAt(0)) {
throw new Error("start > end of charset")
}
const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
set.ranges.push({
start,
end,
len,
})
set.len += len
start = null
end = null
in_range = false
} else if (start !== null && !in_range) {
set.len += 1
set.ranges.push({ start, end: start, len: 1 })
start = null
} else if (start !== null && in_range) {
end = ","
} else if (start === null && end === null && !in_range) {
start = ","
} else {
throw new Error('unexpected ","')
}
break
case "-":
if (start === null) {
start = "-"
} else if (!in_range) {
in_range = true
} else if (in_range && end === null) {
end = "-"
} else {
throw new Error('unexpected "-"')
}
break
default:
if (start === null) {
start = char
} else if (in_range && end === null) {
end = char
} else {
throw new Error(`unexpected "${char}"`)
}
}
}
if (start !== null && end !== null) {
if (start!.charCodeAt(0) > end!.charCodeAt(0)) {
throw new Error("start > end of charset")
}
const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
set.ranges.push({
start,
end,
len,
})
set.len += len
} else if (start !== null) {
set.len += 1
set.ranges.push({
start,
end: start,
len: 1,
})
}
return set
}
type CharSet = {
ranges: {
start: string
end: string
len: number
}[]
len: number
}

View File

@@ -1,4 +1,4 @@
import { Parser } from "ts-matches"
import { Parser, string } from "ts-matches"
import * as T from "../types"
import FileHelper from "./fileHelper"
import nullIfEmpty from "./nullIfEmpty"
@@ -21,6 +21,8 @@ import { LocalBinding } from "../mainFn/LocalBinding"
import { LocalPort } from "../mainFn/LocalPort"
import { NetworkBuilder } from "../mainFn/NetworkBuilder"
import { TorHostname } from "../mainFn/TorHostname"
import { DefaultString } from "../config/configTypes"
import { getDefaultString } from "./getDefaultString"
// prettier-ignore
export type FlattenIntersection<T> =
@@ -42,6 +44,11 @@ export type WrapperDataOptionals<WrapperData, Path extends string> = {
}
export type Utils<WD, WrapperOverWrite = { const: never }> = {
createOrUpdateVault: (opts: {
key: string
value: string | null | undefined
generator: DefaultString
}) => Promise<void>
readFile: <A>(fileHelper: FileHelper<A>) => ReturnType<FileHelper<A>["read"]>
writeFile: <A>(
fileHelper: FileHelper<A>,
@@ -84,6 +91,24 @@ export type Utils<WD, WrapperOverWrite = { const: never }> = {
export const utils = <WrapperData = never, WrapperOverWrite = { const: never }>(
effects: T.Effects,
): Utils<WrapperData, WrapperOverWrite> => ({
createOrUpdateVault: async ({
key,
value,
generator,
}: {
key: string
value: string | null | undefined
generator: DefaultString
}) => {
if (value) {
await effects.vaultSet({ key, value })
return
}
if (await effects.vaultList().then((x) => x.includes(key))) {
return
}
await effects.vaultSet({ key, value: getDefaultString(generator) })
},
getSystemSmtp: () =>
new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite,
readFile: <A>(fileHelper: FileHelper<A>) => fileHelper.read(effects),