From 3904449f45626d2d42be5e50168653dca20835fd Mon Sep 17 00:00:00 2001 From: rhpidfyre Date: Sat, 24 May 2025 21:18:48 -0400 Subject: [PATCH] the user and group system is basically finished, the fs needs progress on creating entries --- src/rt/crypto/generate.ts | 11 +- src/rt/fs.ts | 17 ++- src/rt/rfwfs/groups.ts | 40 ++++-- src/rt/rfwfs/index.ts | 2 +- src/rt/rfwfs/main.ts | 287 ++++++++++++++++++++++---------------- src/rt/rfwfs/users.ts | 169 +++++++++++++++------- 6 files changed, 324 insertions(+), 202 deletions(-) diff --git a/src/rt/crypto/generate.ts b/src/rt/crypto/generate.ts index 79fc798..056a281 100644 --- a/src/rt/crypto/generate.ts +++ b/src/rt/crypto/generate.ts @@ -1,4 +1,6 @@ -type SHA256_String = string +interface SHA256 { + readonly secret: string +} class Crypto { protected inner: string @@ -7,15 +9,16 @@ class Crypto { this.inner = inner } - public async sha256_string(): Promise { + public async sha256_hash(): Promise { const encoder = new TextEncoder() const hash = await crypto.subtle.digest("SHA-256", encoder.encode(this.inner)) const hash_as_uint8 = new Uint8Array(hash) - return Array.from(hash_as_uint8).map(byte => byte.toString(16).padStart(2, "0")).join("") + + return { secret: Array.from(hash_as_uint8).map(byte => byte.toString(16).padStart(2, "0")).join("") } } } export default Crypto export { - type SHA256_String + type SHA256 } \ No newline at end of file diff --git a/src/rt/fs.ts b/src/rt/fs.ts index 1436882..2c62e59 100644 --- a/src/rt/fs.ts +++ b/src/rt/fs.ts @@ -1,16 +1,15 @@ -import rfwfs, { DirectoryInRoot, Permissions } from "./rfwfs/main" +import rfwfs, { PERMISSION_FLAGS } from "./rfwfs/main" const time_now = (Date.now()/1000) | 0 const fs = new rfwfs() -const bin = rfwfs.directory_in_root({ - name: "bin", - timestamp: time_now, - permissions: Permissions.r | Permissions.w -}) - -fs.push_bulk_unsafe([ - bin.dir as DirectoryInRoot +const root = fs.push_bulk_unsafe([ + rfwfs.directory_in_root({ + permissions: {wheel: PERMISSION_FLAGS.RWX, users: PERMISSION_FLAGS.NONE}, + timestamp: time_now, + metadata: {}, + name: "bin" + }) ]) export default fs \ No newline at end of file diff --git a/src/rt/rfwfs/groups.ts b/src/rt/rfwfs/groups.ts index d699c48..b775a52 100644 --- a/src/rt/rfwfs/groups.ts +++ b/src/rt/rfwfs/groups.ts @@ -6,6 +6,8 @@ import User from "./users"; type User_Index = [User, number] type WrapUserSearch = WrapResult +type SysGroupsNames = "wheel" | "users" + const enum SysGroups { Wheel, Users, @@ -36,28 +38,35 @@ interface Groups { class Group { protected inner: User[]; - private type: SysGroups; + private group_type: SysGroups; constructor(type: SysGroups) { - this.type = type + this.group_type = type this.inner = [] } - public get_type(): SysGroups { - return this.type - } - - public get_users(): User[] { + public users(): User[] { return [...this.inner] } + public type(): SysGroups { + return this.group_type + } + public type_as_name(): SysGroupsNames { + return this.type() === SysGroups.Wheel ? "wheel" : "users" + } - public add_user(user: User): void { - this.inner.push(user) + public add_user(user: User): boolean { + const duplicate = this.inner.find(user_in_group => user_in_group.uname() === user.uname()) + if (!duplicate) { + this.inner.push(user) + return true + } + return false } public remove_user(user: User): User | undefined { for (let i = 0; i user.get_uname() === uname) + const found_user = group_t.users().find(user => user.uname() === uname) if (found_user) { group_t.remove_user(found_user) return GroupRemoveStatus.Ok @@ -162,6 +171,7 @@ export { group_wheel_add, group_users_add, group_user_move, + type SysGroupsNames, GroupRemoveStatus, GroupSearch, SysGroups, diff --git a/src/rt/rfwfs/index.ts b/src/rt/rfwfs/index.ts index df3b73e..59a480f 100644 --- a/src/rt/rfwfs/index.ts +++ b/src/rt/rfwfs/index.ts @@ -10,7 +10,7 @@ export default function directory_search(dir_files: T[], file_n let end = dir_files.length-1 while (start<=end) { const median = (start+end)>>1 - const median_name = dir_files[median].name.inner + const median_name = dir_files[median].name.__inner() if (median_name === file_name) { return wrap_bsearch(median, dir_files[median]) diff --git a/src/rt/rfwfs/main.ts b/src/rt/rfwfs/main.ts index 6703944..191c0e6 100644 --- a/src/rt/rfwfs/main.ts +++ b/src/rt/rfwfs/main.ts @@ -1,14 +1,15 @@ import wrap, { type WrapResult, ConstEnum, Option } from "./wrap" -import { Group, SysGroups } from "./groups" +import { SysGroups } from "./groups" import directory_search from "./index" -import User from "./users" +import User, { LibUser } from "./users" const enum EntryType { Root, File, Directory, Binary, + SymLink, } const enum PushStatus { Ok, @@ -18,58 +19,77 @@ const enum PushStatus { const enum ReadStatus { Ok, NotFound, + NotInGroup, Denied, } +const enum ModifyStatus { + Ok, + NotInGroup, + Denied, +} +const enum ModifyAccessType { + Read, + Write, +} const enum ROOT_ID { TRUNK = "/", - NAME = "root" + NAME = "root", + UID = 0, } -const enum Permissions { - r = 1<<0, - w = 1<<1, - x = 1<<2, - rwx = Permissions.r | Permissions.w | Permissions.x +const enum PERMISSION_FLAGS { + NONE = -1, + R = 1 << 0, + W = 1 << 1, + X = 1 << 2, + RWX = PERMISSION_FLAGS.R | PERMISSION_FLAGS.W | PERMISSION_FLAGS.X } -interface EntryPermissions { - group: Group, - owner: User, +interface Permissions, U = Gate> { + wheel: W, + users: U, +} +type GroupPermissionsRoot = Permissions, Gate> + +interface Metadata { + [index: string]: string } -interface Entry> { +interface Entry< + T extends EntryType = EntryType, + P extends Permissions = Permissions, + N = Gate +> { readonly type: T, - permissions: EntryPermissions, - timestamp: number, - name: N -} - -interface DirectoryContainer extends Entry { - files: EntryValue, - parent: T | null + permissions: P, + timestamp: Gate, + metadata: Gate, + group: Gate, + owner: Gate, + name: N, } type Directory = DirectoryContainer> -type DirectoryInRoot = DirectoryContainer -interface Root extends Entry { - timestamp: number, +interface DirectoryContainer extends Entry { + files: Gate, + parent: Gate | null, +} + +interface Root extends Entry { parent: null, - files: EntryValue, + files: Gate, +} + +interface DirectoryInRoot extends Entry, timestamp: number, -} - -interface DirectoryProperties extends DirectoryInRootProperties { - parent: RfwfsDirectory, -} - -interface FileProperties extends Entry { - + metadata: Metadata, + name: string, } /** Other directory types that can be treated as a single arbitrary directory. @@ -85,6 +105,7 @@ type EntryAssociates = Entry | Root type WrapResultEntry = WrapResult type WrapResultNone = WrapResult +type WrapEntryRead = WrapResult function wrap_entry(status: T, result?: U): WrapResultEntry { return wrap(result, status) @@ -94,12 +115,16 @@ function wrap_none(status: T): WrapResultNone { return wrap(Option.None, status) } +function wrap_entry_read(status: ModifyStatus, result?: V): WrapEntryRead { + return wrap(result, status) +} + function fs_dir_sort(dir: DirectoryAssociates) { - dir.files.inner.sort((a,z) => a.name.inner.localeCompare(z.name.inner)) + dir.files.__inner().sort((a,z) => a.name.__inner().localeCompare(z.name.__inner())) } function fs_dir_clone(dir: DirectoryAssociates, file_name: string): WrapResultEntry { - const clone_find = directory_search(dir.files.inner, file_name) + const clone_find = directory_search(dir.files.__inner(), file_name) if (clone_find) { return wrap_entry(ReadStatus.Ok, { ...clone_find.result as T }) } @@ -107,7 +132,7 @@ function fs_dir_clone(dir: DirectoryAssociates, file_name: s } function fs_dir_find(dir: DirectoryAssociates, file_name: string): WrapResultEntry { - const file_search = directory_search(dir.files.inner, file_name) + const file_search = directory_search(dir.files.__inner(), file_name) if (file_search) { return wrap_entry(ReadStatus.Ok, file_search.result as T) } @@ -115,9 +140,9 @@ function fs_dir_find(dir: DirectoryAssociates, file_name: st } function fs_dir_push(dir: DirectoryAssociates, entry: Entry) { - const no_duplicates = directory_search(dir.files.inner, entry.name.inner) + const no_duplicates = directory_search(dir.files.__inner(), entry.name.__inner()) if (!no_duplicates) { - dir.files.inner.push(entry) + dir.files.__inner().push(entry) fs_dir_sort(dir) return wrap_none(PushStatus.Ok) } @@ -125,44 +150,82 @@ function fs_dir_push(dir: DirectoryAssociates, entry: Entry) } function fs_dir_pop(dir: DirectoryAssociates, file_name: string): WrapResultEntry { - const pop_find = directory_search(dir.files.inner, file_name) + const pop_find = directory_search(dir.files.__inner(), file_name) if (pop_find) { - dir.files.inner.splice(pop_find.status, 1) + dir.files.__inner().splice(pop_find.status, 1) return wrap_entry(ReadStatus.Ok, pop_find.result as T) } return wrap_entry(ReadStatus.NotFound) } -class EntryValue { - public inner: V; - protected user_perms: EntryPermissions; +function user_group_perms(entry: EntryAssociates): PERMISSION_FLAGS | undefined { + const user = LibUser.current_sys_user + const current_user_group = user.group() - constructor(user: EntryPermissions, value: V) { + if (user.is_root() || current_user_group.type() === entry.group.__inner()) { + return entry.permissions[current_user_group.type_as_name()].__inner() + } + return undefined +} + +function user_group_read_write(entry: DirectoryAssociates): ModifyStatus { + if (LibUser.current_sys_user.is_root()) { + return ModifyStatus.Ok + } + const group_perms = user_group_perms(entry) + if (group_perms) { + return LibRfwfs.read_write_access(group_perms) ? ModifyStatus.Ok : ModifyStatus.Denied + } + return ModifyStatus.NotInGroup +} + +class Gate { + private inner: V; + protected entry: EntryAssociates; + + constructor(entry: EntryAssociates, value: V) { this.inner = value - this.user_perms = user + this.entry = entry } - private is_wheel_user(user: User): boolean { - return user.get_group() === SysGroups.Wheel + private access_read_write(accessType: ModifyAccessType): ModifyStatus { + const group_perms = user_group_perms(this.entry) + if (group_perms) { + switch (accessType) { + case ModifyAccessType.Read: + return LibRfwfs.read_access(group_perms) ? ModifyStatus.Ok : ModifyStatus.Denied + case ModifyAccessType.Write: + return LibRfwfs.write_access(group_perms) ? ModifyStatus.Ok : ModifyStatus.Denied + } + } + return ModifyStatus.NotInGroup } - public read(): V | undefined { - if (this.is_wheel_user(this.user_perms.owner)) { - return this.inner - } - if (rfwfs_lib.read_access(permissions)) { - - } - return undefined - // return rfwfs_lib.read_access(this.user_perms.permissions) ? this.inner : undefined + public __inner(): V { + return this.inner } - public write(new_value: T): boolean { - if (rfwfs_lib.write_access(this.user_perms.permissions)) { - this.inner = new_value - return true + public read(): WrapEntryRead { + switch (this.access_read_write(ModifyAccessType.Read)) { + case ModifyStatus.Ok: + return wrap_entry_read(ModifyStatus.Ok, this.inner) + case ModifyStatus.NotInGroup: + return wrap_entry_read(ModifyStatus.NotInGroup) + case ModifyStatus.Denied: + return wrap_entry_read(ModifyStatus.Denied) + } + } + + public write(new_value: T): ModifyStatus { + switch (this.access_read_write(ModifyAccessType.Read)) { + case ModifyStatus.Ok: + this.inner = new_value + return ModifyStatus.Ok + case ModifyStatus.NotInGroup: + return ModifyStatus.NotInGroup + case ModifyStatus.Denied: + return ModifyStatus.Denied } - return false } } @@ -178,45 +241,45 @@ class RfwfsDirectory { } public clone(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.dir.permissions)) { + if (user_group_read_write(this.dir)) { return fs_dir_clone(this.dir, file_name) } return wrap_entry(ReadStatus.Denied) } public find(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.dir.permissions)) { + if (user_group_read_write(this.dir)) { return fs_dir_find(this.dir, file_name) } return wrap_entry(ReadStatus.Denied) } public push(entry: E): WrapResultNone { - if (rfwfs.read_write_access(this.dir.permissions)) { + if (user_group_read_write(this.dir)) { return fs_dir_push(this.dir, entry) } return wrap_none(PushStatus.Denied) } public pop(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.dir.permissions)) { + if (user_group_read_write(this.dir)) { fs_dir_pop(this.dir, file_name) } return wrap_entry(ReadStatus.Denied) } public push_bulk_unsafe(dirs: T[]) { - dirs.forEach(dir => this.dir.files.inner.push(dir)) + dirs.forEach(dir => this.dir.files.__inner().push(dir)) this.sort() } public push_unsafe(dir: T) { - this.dir.files.inner.push(dir) + this.dir.files.__inner().push(dir) this.sort() } } -class rfwfs_lib { +class LibRfwfs { public static is_root(entry: T): boolean { return entry.type === EntryType.Root } @@ -229,67 +292,51 @@ class rfwfs_lib { public static is_binary(entry: T): boolean { return entry.type === EntryType.Binary } + public static is_symlink(entry: T): boolean { + return entry.type === EntryType.SymLink + } - public static read_access(permissions: Permissions): boolean { - return (permissions & Permissions.r) !== 0 + public static read_access(permissions: PERMISSION_FLAGS): boolean { + return (permissions & PERMISSION_FLAGS.R) !== 0 } - public static write_access(permissions: Permissions): boolean { - return (permissions & Permissions.w) !== 0 + public static write_access(permissions: PERMISSION_FLAGS): boolean { + return (permissions & PERMISSION_FLAGS.W) !== 0 } - public static execute_access(permissions: Permissions): boolean { - return (permissions & Permissions.x) !== 0 + public static execute_access(permissions: PERMISSION_FLAGS): boolean { + return (permissions & PERMISSION_FLAGS.X) !== 0 } - public static read_write_access(permissions: Permissions): boolean { - return rfwfs.read_access(permissions) && rfwfs.write_access(permissions) + public static read_write_access(permissions: PERMISSION_FLAGS): boolean { + return LibRfwfs.read_access(permissions) && LibRfwfs.write_access(permissions) } public static directory_in_root(properties: DirectoryInRootProperties): RfwfsDirectory { - class dir { - public parent: P; - public permissions: Permissions; - public timestamp: number; - public files: EntryValue; - public name: EntryValue; - - constructor(permissions: Permissions, timestamp: number, name: string, parent: P, files: F[]) { - this.parent = parent - this.permissions = permissions - this.timestamp = timestamp - this.files = new EntryValue(this.permissions, files) - } + const dir_o = { type: EntryType.Directory } as DirectoryInRoot + dir_o.permissions = { + wheel: new Gate(dir_o, properties.permissions.wheel), + users: new Gate(dir_o, properties.permissions.users), } - // const dir_o = { type: EntryType.Directory } as DirectoryInRoot - // dir_o.parent = null - // dir_o.permissions = properties.permissions - // dir_o.timestamp = properties.timestamp - // dir_o.files = new EntryValue(dir_o, []) - // dir_o.name = new EntryValue(dir_o, properties.name) - // return new RfwfsDirectory(dir_o) - } - public static directory(properties: DirectoryProperties): RfwfsDirectory { - const dir_o = { type: EntryType.Directory } as Directory - dir_o.parent = properties.parent - dir_o.permissions = properties.permissions - dir_o.timestamp = properties.timestamp - dir_o.files = new EntryValue(dir_o, []) - dir_o.name = new EntryValue(dir_o, properties.name) + dir_o.metadata = new Gate(dir_o, properties.metadata) + dir_o.timestamp = new Gate(dir_o, properties.timestamp) + dir_o.files = new Gate(dir_o, []) + dir_o.name = new Gate(dir_o, properties.name) + dir_o.parent = null return new RfwfsDirectory(dir_o) } - public static file(properties: FileProperties) { - - } } -class rfwfs extends rfwfs_lib { +class Rfwfs extends LibRfwfs { public root: Root; constructor() { super() this.root = { type: EntryType.Root } as Root - this.root.permissions = Permissions.r | Permissions.w - this.root.timestamp = (Date.now()/1000) | 0 + this.root.permissions = { + wheel: new Gate(this.root, PERMISSION_FLAGS.RWX), + users: new Gate(this.root, PERMISSION_FLAGS.NONE) + } + this.root.timestamp = new Gate(this.root, (Date.now()/1000) | 0) this.root.parent = null - this.root.files = new EntryValue(this.root, []) + this.root.files = new Gate(this.root, []) this.root.name = ROOT_ID.TRUNK } @@ -298,51 +345,51 @@ class rfwfs extends rfwfs_lib { } public clone(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.root.permissions)) { + if (user_group_read_write(this.root)) { return fs_dir_clone(this.root, file_name) } return wrap_entry(ReadStatus.Denied) } public find(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.root.permissions)) { + if (user_group_read_write(this.root)) { return fs_dir_find(this.root, file_name) } return wrap_entry(ReadStatus.Denied) } public push(entry: T): WrapResultNone { - if (rfwfs.read_write_access(this.root.permissions)) { + if (user_group_read_write(this.root)) { return fs_dir_push(this.root, entry) } return wrap_none(PushStatus.Denied) } public pop(file_name: string): WrapResultEntry { - if (rfwfs.read_write_access(this.root.permissions)) { + if (user_group_read_write(this.root)) { fs_dir_pop(this.root, file_name) } return wrap_entry(ReadStatus.Denied) } public push_bulk_unsafe(dirs: DirectoryInRoot[]) { - dirs.forEach(dir => this.root.files.inner.push(dir)) + dirs.forEach(dir => this.root.files.__inner().push(dir)) this.sort() } public push_unsafe(dir: DirectoryInRoot) { - this.root.files.inner.push(dir) + this.root.files.__inner().push(dir) this.sort() } } -export default rfwfs +export default Rfwfs export { type DirectoryInRoot, type RfwfsDirectory, type Directory, type Entry, - Permissions, + PERMISSION_FLAGS, EntryType, ROOT_ID, } \ No newline at end of file diff --git a/src/rt/rfwfs/users.ts b/src/rt/rfwfs/users.ts index a424142..ecc9362 100644 --- a/src/rt/rfwfs/users.ts +++ b/src/rt/rfwfs/users.ts @@ -1,19 +1,41 @@ import { ROOT_ID } from "./main"; -import { Permissions } from "./main"; - -import Crypto, { type SHA256_String } from "../crypto/generate"; -import groups, { groups_find_user, GroupSearch, SysGroups } from "./groups"; +import Crypto, { type SHA256 } from "../crypto/generate"; +import groups, { groups_find_user, GroupSearch, SysGroups, Group } from "./groups"; const enum UserSet { Ok, AlreadyLoggedIn, - UserDoesNotExist + UserDoesNotExist, +} +const enum PasswordCheckStatus { + Ok, + MinBound, + MaxBound, +} +const enum PasswordSetStatus { + Ok, + RootRequiresPassword, + MinBound, + MaxBound, + Incorrect, +} +const enum SetUnameStatus { + Ok, + CantChangeRootName, + NotFound, + WheelResult, + UsersResult, } -let uid_count = 0 +const enum PASS_BOUNDS { + MIN = 4, + MAX = 1 << 12, //64 ^ 2 +} -class user_lib { +let uid_count: number = 0 + +class LibUser { public static current_sys_user: User; public static get_sys_user(): User { @@ -26,94 +48,135 @@ class user_lib { if (!result_user_i) { return UserSet.UserDoesNotExist } if (result_user_i[0].is_logged_in()) { return UserSet.AlreadyLoggedIn } - user_lib.current_sys_user = result_user_i[0] + LibUser.current_sys_user = result_user_i[0] return UserSet.Ok } + + public static in_password_bounds(password: string): PasswordCheckStatus { + //Math.min(Math.max(PASS_BOUNDS.MIN, password.length), PASS_BOUNDS.MAX) < PASS_BOUNDS.MAX + if (password.length > PASS_BOUNDS.MIN) { + if (password.length < PASS_BOUNDS.MAX) { + return PasswordCheckStatus.Ok + } + return PasswordCheckStatus.MaxBound + } + return PasswordCheckStatus.MinBound + } } -class User extends user_lib { - private password?: SHA256_String; +class User { + private inner_password?: SHA256; + private inner_group: Group; + private inner_name: string; + private inner_uid: number; private current: boolean; - private group: SysGroups; - private name: string; - private uid: number; - - public permissions: Permissions; - - constructor(name: string, group: SysGroups, global_perms?: Permissions, password?: SHA256_String) { - super() + constructor(name: string, group: Group, password?: SHA256) { const root_creation = name === ROOT_ID.NAME if (root_creation) { - this.uid = 0 - this.group = SysGroups.Wheel + this.inner_uid = 0 + this.inner_group = group } else { uid_count += 1 - this.uid = uid_count - this.group = group + this.inner_uid = uid_count + this.inner_group = group } - this.name = name + + this.inner_name = name this.current = root_creation - this.password = password - //Wheel users will have all permissions - this.permissions = group === SysGroups.Users ? (global_perms ? global_perms : Permissions.rwx) : Permissions.rwx + this.inner_password = password } private set_as_current(): boolean { - User.get_sys_user().current = false - User.current_sys_user = this + LibUser.get_sys_user().current = false + LibUser.current_sys_user = this this.current = true return this.current } - public get_uid() { - return this.uid - } public is_logged_in(): boolean { return this.current } - public get_group(): SysGroups { - return this.group + public in_wheel(): boolean { + return this.inner_group.type() === SysGroups.Wheel } - public get_uname() { - return this.name + public password(): SHA256 | undefined { + return this.inner_password } - public get_password(): SHA256_String | undefined { - return this.password + public is_root(): boolean { + return this.inner_name === ROOT_ID.NAME && this.inner_uid === ROOT_ID.UID + } + public group(): Group { + return this.inner_group + } + public uname(): string { + return this.inner_name + } + public uid(): number { + return this.inner_uid + } + + public async check_password(password?: string): Promise { + if (!(password && this.inner_password) || (await new Crypto(password).sha256_hash()).secret === this.inner_password.secret) { + return true + } + return false } public async login(password?: string): Promise { - if (!this.password) { - return this.set_as_current() - } - if (password && await new Crypto(password).sha256_string() === this.password) { + if (!this.inner_password || (password && await this.check_password(password))) { return this.set_as_current() } return false } - public set_uname(new_uname: string): GroupSearch { + public set_uname(new_uname: string): SetUnameStatus { + if (this.is_root()) { return SetUnameStatus.CantChangeRootName } + const search = groups_find_user(new_uname) - if (search.status === GroupSearch.NotFound) { - this.name = new_uname + switch (search.status) { + case GroupSearch.NotFound: + this.inner_name = new_uname + break + case GroupSearch.UsersResult: + return SetUnameStatus.UsersResult + case GroupSearch.WheelResult: + return SetUnameStatus.WheelResult } - return search.status + return SetUnameStatus.Ok } - public async set_password(new_password?: string): Promise { - if (new_password) { - this.password = await new Crypto(new_password).sha256_string() - } else { - this.password = undefined + public async set_password(current_password: string, new_password?: string): Promise { + if (await this.check_password(current_password)) { + if (new_password) { + switch (LibUser.in_password_bounds(new_password)) { + case PasswordCheckStatus.Ok: + this.inner_password = await new Crypto(new_password).sha256_hash() + break + case PasswordCheckStatus.MinBound: + return PasswordSetStatus.MinBound + case PasswordCheckStatus.MaxBound: + return PasswordSetStatus.MaxBound + } + } else { + if (this.is_root()) { return PasswordSetStatus.RootRequiresPassword } + //This user has no password + this.inner_password = undefined + } + return PasswordSetStatus.Ok } + return PasswordSetStatus.Incorrect } } groups.wheel.add_user( - new User(ROOT_ID.NAME, SysGroups.Wheel, "90a956efae97cca5ec584977d96a236aa76b0a07def9fcafab87fd221a1d2cfe") + new User(ROOT_ID.NAME, groups.wheel, { secret: "90a956efae97cca5ec584977d96a236aa76b0a07def9fcafab87fd221a1d2cfe" }) ) groups.users.add_user( - new User("user") + new User("user", groups.users) ) -export default User \ No newline at end of file +export default User +export { + LibUser +} \ No newline at end of file