Files
2024-02-25 18:38:02 +00:00

190 lines
6.2 KiB
Plaintext

let packages = {}
let accounts = []
let indexes = {username: {}, email: {}, id: {}}
let savePath = path.join([program.cwd, 'data', "packages-db.json"])
let changes = {n: 0, last: 0}
let validVersion(version) = do
if (version.length < 1 || version.length > 16) return false
for (i from 0 to version.length) do
if (i > 0 && i < version.length-1) do
if (version[i] not in "abcdefghijklmnopqrstuvwxyz0123456789-.") return false
else if (version[i] not in "abcdefghijklmnopqrstuvwxyz0123456789") return false
return true
let validName(name) = do
if (name.length < 3 || name.length > 32) return false
for (i from 0 to name.length) do
if (i > 0 && i < name.length-1) do
if (name[i] not in "abcdefghijklmnopqrstuvwxyz0123456789-.") return false
else if (name[i] not in "abcdefghijklmnopqrstuvwxyz0123456789") return false
return true
let makeChange() = changes.n += 1
let randstr(length) = do
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let str = []
for (i from 0 to length) do
str.append(chars[random.int(0, chars.length-1)])
return str.join("")
let load() = do
if (path.exists(savePath)) do
let file = file.read(savePath)
data = file.json()||{}
if ("packages" not in data) do
packages = data
accounts = []
makeChange()
else do
packages = data.packages
accounts = data.accounts
file.close()
let forceSave() = do
makeChange()
save()
let save() = do
if (changes.n == changes.last) return
changes.last = changes.n
let file = file.write(savePath)
file.json({packages: packages, accounts: accounts})
file.close()
let saveThread() = do
forever do
try do
save()
catch (e) do
term.log(e)
time.snooze(10)
let account = {}
account.addToIndexes(acc, index) = do
indexes.username[acc.username] = index
indexes.email[acc.email] = index
indexes.id[acc.id] = index
account.makeId() = do
let id = "u-"+randstr(32)
if (account.getById(id) != null) return account.makeId()
return id
account.getById(id) = do
if (id in indexes.id) return accounts[indexes.id[id]]
for (i from 0 to accounts.length) do
if (accounts[i].id == id) do
account.addToIndexes(accounts[i], i)
return accounts[i]
return null
account.getByUsername(username) = do
if (username in indexes.username) return accounts[indexes.username[username]]
for (i from 0 to accounts.length) do
if (accounts[i].username == username) do
account.addToIndexes(accounts[i], i)
return accounts[i]
return null
account.getByEmail(email) = do
if (email in indexes.email) return accounts[indexes.email[email]]
for (i from 0 to accounts.length) do
if (accounts[i].email == email) do
account.addToIndexes(accounts[i], i)
return accounts[i]
return null
account.getByToken(token) = do
let split = token.splitN("|", 2)
if (split.length != 2) return null
let id = split[0]
let token = split[1]
let acc = account.getById(id)
if (acc == null) return null
if (token not in acc.tokens) return null
return acc
account.deleteToken(token) = do
let split = token.split("|")
if (split.length != 2) return false
let id = split[0]
let token = split[1]
let acc = account.getById(id)
if (acc == null) return false
if (token not in acc.tokens) return false
acc.tokens = acc.tokens.filter((t) = t != token)
forceSave()
return true
account.makeToken(acc) = do
let token = randstr(100)
acc.tokens.append(token)
makeChange()
return acc.id+"|"+token
account.saltHash(password, salt) = sha256(password+salt)
account.validPassword(password) = do
if (password.length < 8) return "Password must be at least 8 characters"
# include at least one number
let hasNumber = false
for (i from 0 to password.length) do
if (password[i] in "0123456789") do
hasNumber = true
break
if (not hasNumber) return "Password must include at least one number"
# include at least one uppercase letter
if (password.lower() == password) return "Password must include at least one uppercase letter"
# include at least one lowercase letter
if (password.upper() == password) return "Password must include at least one lowercase letter"
return null
account.validEmail(email) = do
let split = email.split("@")
if (split.length != 2) return false
if (split[0].length == 0) return false
if (" " in split[0]) return false
if (split[1].length == 0) return false
if (" " in split[1]) return false
if (split[1].split(".").length < 2) return false
return true
account.validUsername(username) = do
if (username.length < 3) return false
if (username.length > 32) return false
for (i from 0 to username.length) do
if (username[i] not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_") return false
return true
account.create(username, email, password) = do
if (not account.validUsername(username)) return {error: "Invalid username"}
if (not account.validEmail(email)) return {error: "Invalid email"}
if (account.getByUsername(username) != null) return {error: "Username already exists"}
if (account.getByEmail(email) != null) return {error: "Email already exists"}
if ((let error = account.validPassword(password)) != null) return {error: error}
let id = account.makeId()
let salt = randstr(100)
let hash = account.saltHash(password, salt)
let acc = {id: id, username: username, email:email, password: hash, salt: salt, tokens: []}
accounts.append(acc)
forceSave()
return acc
account.login(user, password) = do
let acc = account.getByUsername(user)
if (acc == null) do
acc = account.getByEmail(user)
if (acc == null) return {error: "Icorrect username or email"}
let hash = account.saltHash(password, acc.salt)
if (hash != acc.password) return {error: "Incorrect password"}
return {token: account.makeToken(acc)}
load()
t = thread(saveThread)
t.start()