Merge branch 'main' into new-admin
This commit is contained in:
commit
697df1ca99
27 changed files with 424 additions and 320 deletions
|
@ -1,17 +1,21 @@
|
|||
import {ArrayField, Field, RawJsonField} from "sparkson"
|
||||
import {ClientConfig, JSONObject, Url} from "./shared";
|
||||
|
||||
// TODO: Replace string types by more specific types like URL, Password, etc.
|
||||
import {ClientConfig, DurationMilliseconds, isString, toIsNewtype, Url} from "./shared";
|
||||
|
||||
export type Username = string & { readonly __tag: unique symbol };
|
||||
export const isUsername = toIsNewtype(isString, "" as Username);
|
||||
|
||||
export type CleartextPassword = string & { readonly __tag: unique symbol };
|
||||
export const isCleartextPassword = toIsNewtype(isString, "" as CleartextPassword);
|
||||
|
||||
export type PasswordHash = string & { readonly __tag: unique symbol };
|
||||
export const isPasswordHash = toIsNewtype(isString, "" as PasswordHash);
|
||||
|
||||
export class UsersConfig {
|
||||
constructor(
|
||||
@Field("user") public username: Username,
|
||||
@Field("passwordHash") public passwordHash: PasswordHash,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class LoggingConfig {
|
||||
|
@ -19,51 +23,79 @@ export class LoggingConfig {
|
|||
@Field("enabled") public enabled: boolean,
|
||||
@Field("debug") public debug: boolean,
|
||||
@Field("profile") public profile: boolean,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class InternalConfig {
|
||||
constructor(
|
||||
@Field("active") public active: boolean,
|
||||
@ArrayField("users", UsersConfig) public users: UsersConfig[],
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class SMTPAuthConfig {
|
||||
constructor(
|
||||
@Field("user") public user: Username,
|
||||
@Field("pass") public pass: CleartextPassword,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
// For details see: https://nodemailer.com/smtp/
|
||||
export class SMTPConfig {
|
||||
constructor(
|
||||
@Field("host") public host?: string,
|
||||
@Field("port") public port?: number,
|
||||
@Field("auth") public auth?: SMTPAuthConfig,
|
||||
@Field("secure") public secure?: boolean,
|
||||
@Field("ignoreTLS") public ignoreTLS?: boolean,
|
||||
@Field("requireTLS") public requireTLS?: boolean,
|
||||
@Field("opportunisticTLS") public opportunisticTLS?: boolean,
|
||||
@Field("name") public name?: string,
|
||||
@Field("localAddress") public localAddress?: string,
|
||||
@Field("connectionTimeout") public connectionTimeout?: DurationMilliseconds,
|
||||
@Field("greetingTimeout") public greetingTimeout?: DurationMilliseconds,
|
||||
@Field("socketTimeout") public socketTimeout?: DurationMilliseconds,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class EmailConfig {
|
||||
constructor(
|
||||
@Field("from") public from: string,
|
||||
|
||||
// For details see: https://nodemailer.com/2-0-0-beta/setup-smtp/
|
||||
@RawJsonField("smtp") public smtp: JSONObject,
|
||||
) {}
|
||||
@RawJsonField("smtp") public smtp: SMTPConfig,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class ServerMapConfig {
|
||||
constructor(
|
||||
@ArrayField("nodesJsonUrl", String) public nodesJsonUrl: Url[],
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class ServerConfig {
|
||||
constructor(
|
||||
@Field("baseUrl") public baseUrl: Url,
|
||||
@Field("port") public port: number,
|
||||
|
||||
@Field("databaseFile") public databaseFile: string,
|
||||
@Field("peersPath") public peersPath: string,
|
||||
|
||||
@Field("logging") public logging: LoggingConfig,
|
||||
@Field("internal") public internal: InternalConfig,
|
||||
@Field("email") public email: EmailConfig,
|
||||
@Field("map") public map: ServerMapConfig,
|
||||
|
||||
@Field("rootPath", true, undefined, "/") public rootPath: string,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class Config {
|
||||
constructor(
|
||||
@Field("server") public server: ServerConfig,
|
||||
@Field("client") public client: ClientConfig,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
Domain,
|
||||
DomainSpecificNodeResponse,
|
||||
EmailAddress,
|
||||
isNumber,
|
||||
JSONObject,
|
||||
MonitoringResponse,
|
||||
MonitoringState,
|
||||
|
@ -13,6 +14,7 @@ import {
|
|||
Site,
|
||||
StoredNode,
|
||||
toIsEnum,
|
||||
toIsNewtype,
|
||||
} from "./shared";
|
||||
|
||||
export * from "./config";
|
||||
|
@ -21,8 +23,8 @@ export * from "./logger";
|
|||
export * from "./shared";
|
||||
|
||||
export type NodeStateData = {
|
||||
site: Site,
|
||||
domain: Domain,
|
||||
site?: Site,
|
||||
domain?: Domain,
|
||||
state: OnlineState,
|
||||
}
|
||||
|
||||
|
@ -90,12 +92,13 @@ export function toMonitoringResponse(node: StoredNode): MonitoringResponse {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: Complete interface / class declaration.
|
||||
export type NodeSecrets = {
|
||||
monitoringToken?: MonitoringToken,
|
||||
};
|
||||
|
||||
export type MailId = number & { readonly __tag: unique symbol };
|
||||
export const isMailId = toIsNewtype(isNumber, NaN as MailId);
|
||||
|
||||
export type MailData = JSONObject;
|
||||
|
||||
export enum MailType {
|
||||
|
@ -108,12 +111,11 @@ export enum MailType {
|
|||
|
||||
export const isMailType = toIsEnum(MailType);
|
||||
|
||||
export interface Mail {
|
||||
id: MailId,
|
||||
email: MailType,
|
||||
sender: EmailAddress,
|
||||
recipient: EmailAddress,
|
||||
data: MailData,
|
||||
failures: number,
|
||||
export type Mail = {
|
||||
id: MailId;
|
||||
email: MailType;
|
||||
sender: EmailAddress;
|
||||
recipient: EmailAddress;
|
||||
data: MailData;
|
||||
failures: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,13 @@ export function isString(arg: unknown): arg is string {
|
|||
return typeof arg === "string"
|
||||
}
|
||||
|
||||
export function toIsNewtype<
|
||||
Type extends Value & { readonly __tag: symbol },
|
||||
Value,
|
||||
>(isValue: TypeGuard<Value>, _example: Type): TypeGuard<Type> {
|
||||
return (arg: unknown): arg is Type => isValue(arg);
|
||||
}
|
||||
|
||||
export function isNumber(arg: unknown): arg is number {
|
||||
return typeof arg === "number"
|
||||
}
|
||||
|
@ -109,18 +116,22 @@ export function toIsEnum<E>(enumDef: E): EnumTypeGuard<E> {
|
|||
return (arg): arg is EnumValue<E> => Object.values(enumDef).includes(arg as [keyof E]);
|
||||
}
|
||||
|
||||
export function isRegExp(arg: unknown): arg is RegExp {
|
||||
return isObject(arg) && arg instanceof RegExp;
|
||||
}
|
||||
|
||||
export function isOptional<T>(arg: unknown, isT: TypeGuard<T>): arg is (T | undefined) {
|
||||
return arg === undefined || isT(arg);
|
||||
}
|
||||
|
||||
export type Url = string & { readonly __tag: unique symbol };
|
||||
export const isUrl = isString;
|
||||
export const isUrl = toIsNewtype(isString, "" as Url);
|
||||
|
||||
export type Version = string & { readonly __tag: unique symbol };
|
||||
export const isVersion = isString;
|
||||
export const isVersion = toIsNewtype(isString, "" as Version);
|
||||
|
||||
export type EmailAddress = string & { readonly __tag: unique symbol };
|
||||
export const isEmailAddress = isString;
|
||||
export const isEmailAddress = toIsNewtype(isString, "" as EmailAddress);
|
||||
|
||||
export type NodeStatistics = {
|
||||
registered: number;
|
||||
|
@ -321,31 +332,33 @@ export function isClientConfig(arg: unknown): arg is ClientConfig {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: Token type.
|
||||
export type Token = string & { readonly __tag: unique symbol };
|
||||
export const isToken = isString;
|
||||
export const isToken = toIsNewtype(isString, "" as Token);
|
||||
|
||||
export type FastdKey = string & { readonly __tag: unique symbol };
|
||||
export const isFastdKey = isString;
|
||||
export const isFastdKey = toIsNewtype(isString, "" as FastdKey);
|
||||
|
||||
export type MAC = string & { readonly __tag: unique symbol };
|
||||
export const isMAC = isString;
|
||||
export const isMAC = toIsNewtype(isString, "" as MAC);
|
||||
|
||||
export type DurationSeconds = number & { readonly __tag: unique symbol };
|
||||
export const isDurationSeconds = isNumber;
|
||||
export const isDurationSeconds = toIsNewtype(isNumber, NaN as DurationSeconds);
|
||||
|
||||
export type DurationMilliseconds = number & { readonly __tag: unique symbol };
|
||||
export const isDurationMilliseconds = toIsNewtype(isNumber, NaN as DurationMilliseconds);
|
||||
|
||||
export type UnixTimestampSeconds = number & { readonly __tag: unique symbol };
|
||||
export const isUnixTimestampSeconds = isNumber;
|
||||
export const isUnixTimestampSeconds = toIsNewtype(isNumber, NaN as UnixTimestampSeconds);
|
||||
|
||||
export type UnixTimestampMilliseconds = number & { readonly __tag: unique symbol };
|
||||
export const isUnixTimestampMilliseconds = isNumber;
|
||||
export const isUnixTimestampMilliseconds = toIsNewtype(isNumber, NaN as UnixTimestampMilliseconds);
|
||||
|
||||
export function toUnixTimestampSeconds(ms: UnixTimestampMilliseconds): UnixTimestampSeconds {
|
||||
return Math.floor(ms) as UnixTimestampSeconds;
|
||||
}
|
||||
|
||||
export type MonitoringToken = string & { readonly __tag: unique symbol };
|
||||
export const isMonitoringToken = isString;
|
||||
export const isMonitoringToken = toIsNewtype(isString, "" as MonitoringToken);
|
||||
|
||||
export enum MonitoringState {
|
||||
ACTIVE = "active",
|
||||
|
@ -356,15 +369,16 @@ export enum MonitoringState {
|
|||
export const isMonitoringState = toIsEnum(MonitoringState);
|
||||
|
||||
export type NodeId = string & { readonly __tag: unique symbol };
|
||||
export const isNodeId = toIsNewtype(isString, "" as NodeId);
|
||||
|
||||
export type Hostname = string & { readonly __tag: unique symbol };
|
||||
export const isHostname = isString;
|
||||
export type Hostname = string & { readonly __tag: unique symbol }
|
||||
export const isHostname = toIsNewtype(isString, "" as Hostname);
|
||||
|
||||
export type Nickname = string & { readonly __tag: unique symbol };
|
||||
export const isNickname = isString;
|
||||
export const isNickname = toIsNewtype(isString, "" as Nickname);
|
||||
|
||||
export type Coordinates = string & { readonly __tag: unique symbol };
|
||||
export const isCoordinates = isString;
|
||||
export const isCoordinates = toIsNewtype(isString, "" as Coordinates);
|
||||
|
||||
/**
|
||||
* Basic node data.
|
||||
|
@ -473,10 +487,10 @@ export enum OnlineState {
|
|||
export const isOnlineState = toIsEnum(OnlineState);
|
||||
|
||||
export type Site = string & { readonly __tag: unique symbol };
|
||||
export const isSite = isString;
|
||||
export const isSite = toIsNewtype(isString, "" as Site);
|
||||
|
||||
export type Domain = string & { readonly __tag: unique symbol };
|
||||
export const isDomain = isString;
|
||||
export const isDomain = toIsNewtype(isString, "" as Domain);
|
||||
|
||||
/**
|
||||
* Represents a node in the context of a Freifunk site and domain.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue