mirror of
https://onedev.site.tesses.net/crosslang/crosslangextras
synced 2026-02-08 17:15:45 +00:00
Add reference
This commit is contained in:
219
Tesses.CrossLang.PackageServer/src/backend/accounts.tcross
Normal file
219
Tesses.CrossLang.PackageServer/src/backend/accounts.tcross
Normal file
@@ -0,0 +1,219 @@
|
||||
func DB.ChangeMotto(userId, motto)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
Sqlite.Exec(dbCon,$"UPDATE accounts SET motto = {Sqlite.Escape(motto)} WHERE id = {userId};");
|
||||
var account = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE id = {userId};");
|
||||
DB.Unlock();
|
||||
if(TypeOf(account) == "List" && account.Length > 0)
|
||||
{
|
||||
return $"/account?name={Net.Http.UrlEncode(account[0].accountName)}";
|
||||
}
|
||||
return "/";
|
||||
}
|
||||
func DB.LoginButton(ctx,active,$accountPage)
|
||||
{
|
||||
var session = DB.GetSession(ctx);
|
||||
|
||||
|
||||
if(session != null)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions s inner join accounts a on s.accountId = a.id WHERE key = {Sqlite.Escape(session)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var active2 = TypeOf(accountPage) == "String" ? accountPage == exec[0].accountName : false;
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
return {
|
||||
active=active2,
|
||||
route = $"/account?name={Net.Http.UrlEncode(exec[0].accountName)}",
|
||||
text = exec[0].accountName,
|
||||
admin = (ParseLong(exec[0].flags) & DB.FLAG_ADMIN) != 0,
|
||||
session=session
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
active,
|
||||
route = "/login",
|
||||
text = "Login",
|
||||
admin = false,
|
||||
session=""
|
||||
};
|
||||
}
|
||||
func DB.GetUserInfo(userId)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon, $"SELECT * FROM accounts WHERE id = {userId};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
var data = exec[0];
|
||||
data.flags = ParseLong(data.flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
func DB.CreateUserFromAdmin(email, name, password, flags)
|
||||
{
|
||||
var res = {Success=true};
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
res = {Success=false, Reason = "Name already exists"};
|
||||
}
|
||||
else if((flags & DB.FLAG_VERIFIED) != 0)
|
||||
{
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{0},{flags});");
|
||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||
res = {Success=true};
|
||||
}
|
||||
else {
|
||||
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{DateTime.NowEpoch+600},{flags});");
|
||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||
|
||||
if(DB.Config.MailConfig)
|
||||
DB.SendVerifyEmail(email,name, verify_hash_str);
|
||||
|
||||
res = {Success=true};
|
||||
}
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return res;
|
||||
}
|
||||
func DB.CreateUser(email, name, password)
|
||||
{
|
||||
var res = {Success = true, Redirect="/"};
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
if(Sqlite.Exec(dbCon, "SELECT * FROM accounts LIMIT 1;").Length == 0)
|
||||
{
|
||||
//create the admin
|
||||
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{DB.FLAG_ADMIN|DB.FLAG_VERIFIED});");
|
||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE email = {Sqlite.Escape(email)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
res = {Success=false, Reason = "Email and Name already exists"};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = {Success=false, Reason = "Email already exists"};
|
||||
}
|
||||
}
|
||||
else {
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
res = {Success=false, Reason = "Name already exists"};
|
||||
}
|
||||
else if(DB.Config.AllowRegister)
|
||||
{
|
||||
//email and name already exists
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, verifyExpire, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{DateTime.NowEpoch+600},{DB.FLAG_VERIFY});");
|
||||
if(TypeOf(r) == "String") {res = {Success = false, Reason = r};}
|
||||
else {
|
||||
if(DB.Config.MailConfig)
|
||||
DB.SendVerifyEmail(email,name, verify_hash_str);
|
||||
|
||||
res = {Success=true, Redirect="/check_email"};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = {Success=false, Reason="Registration is disabled on this server"};
|
||||
}
|
||||
}
|
||||
}
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return res;
|
||||
}
|
||||
func DB.GetAccountId(email, password)
|
||||
{
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE email = {Sqlite.Escape(email)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var correct=false;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
var salt = Crypto.Base64Decode(exec[0].password_salt);
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
var hashStr = Crypto.Base64Encode(hash);
|
||||
|
||||
if(exec[0].password_hash == hashStr)
|
||||
{
|
||||
return ParseLong(exec[0].id);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
func DB.GetAccountInfo(name)
|
||||
{
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
return exec[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return "No such user exists";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
@@ -3,347 +3,7 @@ func DB.Open()
|
||||
var path = DB.working / "data.db";
|
||||
return Sqlite.Open(path);
|
||||
}
|
||||
func DB.ChangeMotto(userId, motto)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
Sqlite.Exec(dbCon,$"UPDATE accounts SET motto = {Sqlite.Escape(motto)} WHERE id = {userId};");
|
||||
var account = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE id = {userId};");
|
||||
DB.Unlock();
|
||||
if(TypeOf(account) == "List" && account.Length > 0)
|
||||
{
|
||||
return $"/account?name={Net.Http.UrlEncode(account[0].accountName)}";
|
||||
}
|
||||
return "/";
|
||||
}
|
||||
func DB.LoginButton(ctx,active,$accountPage)
|
||||
{
|
||||
var session = DB.GetSession(ctx);
|
||||
|
||||
|
||||
if(session != null)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions s inner join accounts a on s.accountId = a.id WHERE key = {Sqlite.Escape(session)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var active2 = TypeOf(accountPage) == "String" ? accountPage == exec[0].accountName : false;
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
return {
|
||||
active=active2,
|
||||
route = $"/account?name={Net.Http.UrlEncode(exec[0].accountName)}",
|
||||
text = exec[0].accountName
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
active,
|
||||
route = "/login",
|
||||
text = "Login"
|
||||
};
|
||||
}
|
||||
|
||||
func DB.CanUploadPackagePrefix(userId, packageName)
|
||||
{
|
||||
var prefix = packageName.Split(".",true,2);
|
||||
if(prefix.Length >= 1)
|
||||
prefix = prefix[0];
|
||||
else return false;
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon, $"SELECT * FROM reserved_prefixes WHERE prefix = {Sqlite.Escape(prefix)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0) return ParseLong(exec[0].accountId) == userId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
func DB.GetUserInfo(userId)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon, $"SELECT * FROM sessions WHERE id = {userId};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
var data = exec[0];
|
||||
data.flags = ParseLong(data.flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
func DB.PackageExists(userId,pkgInfo)
|
||||
{
|
||||
var statusCode = 4;
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * from packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
var pkgId = exec[0].id;
|
||||
if(ParseLong(exec[0].accountId) != userId)
|
||||
statusCode=4;
|
||||
else
|
||||
{
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * from versions WHERE packageId = {pkgId} AND version = {pkgInfo.Version.VersionInt};");
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
if(pkgInfo.Version.Stage == "dev")
|
||||
statusCode=3;
|
||||
else
|
||||
statusCode=2;
|
||||
}
|
||||
else statusCode=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else statusCode=0;
|
||||
}
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return statusCode;
|
||||
}
|
||||
func DB.AddPackage(userId,pkgInfo)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
Sqlite.Exec(dbCon,$"INSERT INTO packages (packageName, accountId) VALUES ({Sqlite.Escape(pkgInfo.Name)}, {userId});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
func DB.UpdateVersion(pkgInfo)
|
||||
{
|
||||
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
var pkgId = 0;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
pkgId = exec[0].id;
|
||||
}
|
||||
var version = pkgInfo.Version.VersionInt;
|
||||
var info = Json.Decode(pkgInfo.Info);
|
||||
var description = info.description;
|
||||
var type = info.type;
|
||||
var maintainer = info.maintainer;
|
||||
var homepage = info.homepage;
|
||||
var repo = info.repo;
|
||||
var license = info.license;
|
||||
if(TypeOf(description) != "String") description="";
|
||||
|
||||
if(TypeOf(type) != "String") type="";
|
||||
|
||||
if(TypeOf(maintainer) != "String") maintainer="";
|
||||
|
||||
if(TypeOf(homepage) != "String") homepage="";
|
||||
|
||||
if(TypeOf(repo) != "String") repo="";
|
||||
|
||||
if(TypeOf(license) != "String") license="";
|
||||
|
||||
//CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT);
|
||||
//VALUES ({pkgId},{version},{Sqlite.Escape(description)},{Sqlite.Escape(type)},{Sqlite.Escape(maintainer)},{Sqlite.Escape(homepage)},{Sqlite.Escape(repo)},{Sqlite.Escape(license)});
|
||||
Sqlite.Exec(dbCon,$"UPDATE versions SET description = {Sqlite.Escape(description)}, type = {Sqlite.Escape(type)}, maintainer = {Sqlite.Escape(maintainer)}, homepage = {Sqlite.Escape(homepage)}, repo = {Sqlite.Escape(repo)}, license = {Sqlite.Escape(license)}, uploadTime = {DateTime.NowEpoch} WHERE packageId = {pkgId} AND version = {version};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
func DB.AddVersion(pkgInfo)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
var pkgId = 0;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
pkgId = exec[0].id;
|
||||
}
|
||||
var version = pkgInfo.Version.VersionInt;
|
||||
var info = Json.Decode(pkgInfo.Info);
|
||||
var description = info.description;
|
||||
var type = info.type;
|
||||
var maintainer = info.maintainer;
|
||||
var homepage = info.homepage;
|
||||
var repo = info.repo;
|
||||
var license = info.license;
|
||||
if(TypeOf(description) != "String") description="";
|
||||
|
||||
if(TypeOf(type) != "String") type="";
|
||||
|
||||
if(TypeOf(maintainer) != "String") maintainer="";
|
||||
|
||||
if(TypeOf(homepage) != "String") homepage="";
|
||||
|
||||
if(TypeOf(repo) != "String") repo="";
|
||||
|
||||
if(TypeOf(license) != "String") license="";
|
||||
|
||||
//CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT);
|
||||
|
||||
Sqlite.Exec(dbCon,$"INSERT INTO versions (packageId,version,description,type,maintainer,homepage,repo,license,uploadTime) VALUES ({pkgId},{version},{Sqlite.Escape(description)},{Sqlite.Escape(type)},{Sqlite.Escape(maintainer)},{Sqlite.Escape(homepage)},{Sqlite.Escape(repo)},{Sqlite.Escape(license)},{DateTime.NowEpoch});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
func DB.GetPackageIcon(name, version)
|
||||
{
|
||||
if(TypeOf(name) != "String") name = "";
|
||||
if(TypeOf(version) != "String") version = "";
|
||||
|
||||
var file = DB.working / "Packages" / name / $"{name}-{version}.crvm";
|
||||
|
||||
|
||||
if(FS.Local.FileExists(file) && name.Length > 0 && version.Length > 0)
|
||||
{
|
||||
var strm = FS.Local.OpenFile(file,"rb");
|
||||
|
||||
if(strm != null)
|
||||
{
|
||||
var exec = VM.LoadExecutable(strm);
|
||||
strm.Close();
|
||||
if(exec != null)
|
||||
{
|
||||
if(exec.Icon != null)
|
||||
{
|
||||
return exec.Icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return embed("crosslang.png");
|
||||
}
|
||||
func DB.UploadPackage(userId, filePath)
|
||||
{
|
||||
if(!FS.Local.FileExists(filePath)) return {Success=false, Reason = "File does not exist"};
|
||||
var userInfo = DB.GetUserInfo(userId);
|
||||
if(userInfo == null) return { Success=false, Reason = "User does not exist"};
|
||||
if((userInfo.flags & DB.FLAG_VERIFIED) == 0) return { Success=false, Reason = "User is not verified"};
|
||||
|
||||
var strm = FS.Local.OpenFile(filePath,"rb");
|
||||
var failed=false;
|
||||
var reason = "";
|
||||
try {
|
||||
var pkgInfo = VM.LoadExecutable(strm);
|
||||
}catch(ex) {
|
||||
if(ex.Type == "NativeException")
|
||||
reason = ex.Text;
|
||||
|
||||
failed=true;
|
||||
}
|
||||
|
||||
strm.Close();
|
||||
if(failed) return {Success=false, Reason = reason};
|
||||
if(!DB.CanUploadPackagePrefix(userId,pkgInfo.Name)) return { Success = false, Reason = "You can't upload a package with that prefix."};
|
||||
|
||||
switch(DB.PackageExists(userId, pkgInfo))
|
||||
{
|
||||
case 0:
|
||||
//package name does not exist
|
||||
DB.AddPackage(userId,pkgInfo);
|
||||
case 1:
|
||||
DB.AddVersion(pkgInfo);
|
||||
FS.Local.CreateDirectory(DB.working / "Packages" / pkgInfo.Name);
|
||||
|
||||
FS.Local.MoveFile(filePath, DB.working / "Packages" / pkgInfo.Name / $"{pkgInfo.Name}-{pkgInfo.Version}.crvm");
|
||||
|
||||
|
||||
//package version does not exist
|
||||
break;
|
||||
case 2:
|
||||
return { Success = false, Reason = "Package already exists and is not a dev package." };
|
||||
case 3:
|
||||
//update package version (it exists but is dev)
|
||||
|
||||
DB.UpdateVersion(pkgInfo);
|
||||
FS.Local.MoveFile(filePath, DB.working / "Packages" / pkgInfo.Name / $"{pkgInfo.Name}-{pkgInfo.Version}.crvm");
|
||||
break;
|
||||
case 4:
|
||||
//package is not yours
|
||||
return { Success = false, Reason = "You don't own the package."};
|
||||
}
|
||||
|
||||
return {Success=true};
|
||||
}
|
||||
|
||||
func DB.GetUserIdFromSession(session)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1) return ParseLong(exec[0].accountId);
|
||||
|
||||
return -1;
|
||||
}
|
||||
func DB.GetSessionFromBearer(ctx)
|
||||
{
|
||||
var auth = ctx.RequestHeaders.TryGetFirst("Authorization");
|
||||
if(TypeOf(auth) == "String")
|
||||
{
|
||||
auth=auth.Split(" ",true,2);
|
||||
if(auth.Length < 2) return null;
|
||||
if(auth[0] != "Bearer") return null;
|
||||
var uid = DB.GetUserIdFromSession(auth[1]);
|
||||
if(uid != -1) return auth[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.GetSession(ctx)
|
||||
{
|
||||
var cookie = ctx.RequestHeaders.TryGetFirst("Cookie");
|
||||
if(TypeOf(cookie) == "String")
|
||||
{
|
||||
each(var part : cookie.Split("; "))
|
||||
{
|
||||
if(part.Length > 0)
|
||||
{
|
||||
var cookieKV = part.Split("=",true,2);
|
||||
if(cookieKV.Length == 2 && cookieKV[0] == "Session")
|
||||
{
|
||||
var session = cookieKV[1];
|
||||
var sessionId = DB.GetUserIdFromSession(session);
|
||||
|
||||
if(sessionId != -1)
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.CreateSession(userId)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
|
||||
var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG")));
|
||||
Sqlite.Exec(dbCon, $"INSERT INTO sessions (accountId,key) VALUES ({userId},{Sqlite.Escape(rand)});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return rand;
|
||||
}
|
||||
func DB.CreateCSRF(ctx)
|
||||
{
|
||||
var session = DB.GetSession(ctx);
|
||||
@@ -391,48 +51,7 @@ func DB.VerifyCSRF(session,csrf)
|
||||
DB.Unlock();
|
||||
return retVal;
|
||||
}
|
||||
func DB.GetLatestVersion(name)
|
||||
{
|
||||
var sql = $"SELECT * FROM packages p join versions v on p.id = v.packageId and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId) and p.packageName = {Sqlite.Escape(name)};";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(res) == "List" && res.Length > 0)
|
||||
{
|
||||
return Version.FromLong(ParseLong(res[0].version)).ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.GetPackages($page)
|
||||
{
|
||||
if(TypeOf(page) != "Long") page = 1;
|
||||
|
||||
var sql = "SELECT * FROM packages p join versions v on p.id = v.packageId and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId);";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var res2 = [];
|
||||
each(var item : res)
|
||||
{
|
||||
res2.Add({
|
||||
id = item.packageId,
|
||||
name = item.packageName,
|
||||
version = Version.FromLong(ParseLong(item.version)).ToString(),
|
||||
homepage = item.homepage,
|
||||
repo = item.repo,
|
||||
type = item.type,
|
||||
maintainer = item.maintainer,
|
||||
description = item.description
|
||||
});
|
||||
}
|
||||
return res2;
|
||||
}
|
||||
|
||||
func DB.Lock()
|
||||
{
|
||||
@@ -480,6 +99,8 @@ func DB.Init(working)
|
||||
DB.Config = {
|
||||
AllowRegister=false,
|
||||
};
|
||||
|
||||
if(TypeOf(DB.Config) != "Dictionary") DB.Config = {AllowRegister=false};
|
||||
|
||||
var dbCon = DB.Open();
|
||||
Sqlite.Exec(dbCon,"CREATE TABLE IF NOT EXISTS packages (id INTEGER PRIMARY KEY AUTOINCREMENT, packageName TEXT UNIQUE, accountId INTEGER);");
|
||||
@@ -498,204 +119,5 @@ DB.FLAG_VERIFY = 0b00000100;
|
||||
|
||||
DB.ITTR = 35000;
|
||||
|
||||
func DB.GetAccountInfo(name)
|
||||
{
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
return exec[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return "No such user exists";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
|
||||
func DB.GetAccountId(email, password)
|
||||
{
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE email = {Sqlite.Escape(email)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var correct=false;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
var salt = Crypto.Base64Decode(exec[0].password_salt);
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
var hashStr = Crypto.Base64Encode(hash);
|
||||
|
||||
if(exec[0].password_hash == hashStr)
|
||||
{
|
||||
return ParseLong(exec[0].id);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
func DB.SendVerifyEmail(email,name, verify_hash_str)
|
||||
{
|
||||
var emailText = $"
|
||||
<h1>Hello {Net.Http.HtmlEncode(name)}</h1>
|
||||
<span>To verify your account go to <a href=\"{DB.Config.Prefix.TrimEnd('/')}/verify?code={Net.Http.UrlEncode(verify_hash_str)}\">{DB.Config.Prefix.TrimEnd('/')}/verify?code={Net.Http.UrlEncode(verify_hash_str)}</a></span>
|
||||
";
|
||||
var data = {
|
||||
server = DB.Config.MailConfig.Server,
|
||||
auth = DB.Config.MailConfig.Auth,
|
||||
domain = DB.Config.MailConfig.Domain,
|
||||
from = DB.Config.MailConfig.From,
|
||||
to = email.Replace(">","").Replace("\n",""),
|
||||
subject = "Verify your account on CPKG",
|
||||
body = {
|
||||
type = "text/html",
|
||||
data = emailText
|
||||
}
|
||||
};
|
||||
Net.Smtp.Send(data);
|
||||
}
|
||||
|
||||
func DB.CreateUser(email, name, password)
|
||||
{
|
||||
var res = {Success = true, Redirect="/"};
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
if(Sqlite.Exec(dbCon, "SELECT * FROM accounts LIMIT 1;").Length == 0)
|
||||
{
|
||||
//create the admin
|
||||
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{DB.FLAG_ADMIN|DB.FLAG_VERIFIED});");
|
||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE email = {Sqlite.Escape(email)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
res = {Success=false, Reason = "Email and Name already exists"};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = {Success=false, Reason = "Email already exists"};
|
||||
}
|
||||
}
|
||||
else {
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(name)};");
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0)
|
||||
{
|
||||
res = {Success=false, Reason = "Name already exists"};
|
||||
}
|
||||
else if(DB.Config.AllowRegister)
|
||||
{
|
||||
//email and name already exists
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||
|
||||
var r = Sqlite.Exec(dbCon,$"INSERT INTO accounts (email, accountName, password_hash, password_salt, verifyKey, flags) values ({Sqlite.Escape(email)},{Sqlite.Escape(name)},{Sqlite.Escape(Crypto.Base64Encode(hash))},{Sqlite.Escape(Crypto.Base64Encode(salt))},{Sqlite.Escape(verify_hash_str)},{DB.FLAG_VERIFY});");
|
||||
if(TypeOf(r) == "String") res = {Success = false, Reason = r};
|
||||
|
||||
if(DB.Config.MailConfig)
|
||||
DB.SendVerifyEmail(email,name, verify_hash_str);
|
||||
|
||||
res = {Success=true, Redirect="/check_email"};
|
||||
}
|
||||
else
|
||||
{
|
||||
res = {Success=false, Reason="Registration is disabled on this server"};
|
||||
}
|
||||
}
|
||||
}
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return res;
|
||||
}
|
||||
func DB.GetPackageVersions(name)
|
||||
{
|
||||
var sql = $"SELECT * FROM packages p inner join versions v on p.id = v.packageId inner join accounts a on p.accountId = a.id WHERE p.packageName = {Sqlite.Escape(name)} ORDER BY v.version DESC;";
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
var list = [];
|
||||
each(var item : res)
|
||||
{
|
||||
var version = Version.FromLong(ParseLong(item.version)).ToString();
|
||||
var uploadTime = ParseLong(item.uploadTime);
|
||||
list.Add({
|
||||
version,
|
||||
download = $"./api/v1/download?name={Net.Http.UrlEncode(name)}&version={Net.Http.UrlEncode(version)}",
|
||||
accountName = item.accountName,
|
||||
description = item.description,
|
||||
maintainer = item.maintainer,
|
||||
type = item.type,
|
||||
repo = item.repo,
|
||||
homepage = item.homepage,
|
||||
license = item.license,
|
||||
uploadTime,
|
||||
uploadDate=Time.UTCUsSlashDate(uploadTime)
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
func DB.QueryPackages(q, offset, limit)
|
||||
{
|
||||
if(TypeOf(offset) != "Long") offset = 0;
|
||||
if(TypeOf(limit) != "Long") limit = 20;
|
||||
var q2 = Sqlite.Escape($"%{q}%");
|
||||
var sql = $"SELECT * FROM packages p inner join versions v on p.id = v.packageId and (p.packageName LIKE {q2} OR v.description LIKE {q2}) and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId) INNER JOIN accounts a on a.id = p.accountId LIMIT {limit} OFFSET {offset};";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
var res2=[];
|
||||
each(var item : res)
|
||||
{
|
||||
var uploadTime = ParseLong(item.uploadTime);
|
||||
res2.Add({
|
||||
accountName = item.accountName,
|
||||
description = item.description,
|
||||
homepage = item.homepage,
|
||||
license = item.license,
|
||||
maintainer = item.maintainer,
|
||||
packageName = item.packageName,
|
||||
uploadTime,
|
||||
uploadDate = Time.UTCUsSlashDate(uploadTime),
|
||||
repo = item.repo,
|
||||
type = item.type,
|
||||
version = Version.FromLong(ParseLong(item.version)).ToString()
|
||||
});
|
||||
}
|
||||
return res2;
|
||||
}
|
||||
171
Tesses.CrossLang.PackageServer/src/backend/email.tcross
Normal file
171
Tesses.CrossLang.PackageServer/src/backend/email.tcross
Normal file
@@ -0,0 +1,171 @@
|
||||
func DB.SendVerifyEmail(email,name, verify_hash_str)
|
||||
{
|
||||
var emailText = $"
|
||||
<h1>Hello {Net.Http.HtmlEncode(name)}</h1>
|
||||
<span>To verify your account go to <a href=\"{DB.Config.Prefix.TrimEnd('/')}/verify?code={Net.Http.UrlEncode(verify_hash_str)}\">{DB.Config.Prefix.TrimEnd('/')}/verify?code={Net.Http.UrlEncode(verify_hash_str)}</a></span>
|
||||
";
|
||||
var data = {
|
||||
server = DB.Config.MailConfig.Server,
|
||||
auth = DB.Config.MailConfig.Auth,
|
||||
domain = DB.Config.MailConfig.Domain,
|
||||
from = DB.Config.MailConfig.From,
|
||||
to = email.Replace(">","").Replace("\n",""),
|
||||
subject = "Verify your account on CPKG",
|
||||
body = {
|
||||
type = "text/html",
|
||||
data = emailText
|
||||
}
|
||||
};
|
||||
Net.Smtp.Send(data);
|
||||
}
|
||||
func DB.SendForgotPasswordEmail(email,name, verify_hash_str)
|
||||
{
|
||||
var emailText = $"
|
||||
<h1>Hello {Net.Http.HtmlEncode(name)}</h1>
|
||||
<p>This will expire in 10 minutes</p>
|
||||
<span>To reset your password go to <a href=\"{DB.Config.Prefix.TrimEnd('/')}/new_password?code={Net.Http.UrlEncode(verify_hash_str)}\">{DB.Config.Prefix.TrimEnd('/')}/new_password?code={Net.Http.UrlEncode(verify_hash_str)}</a></span>
|
||||
";
|
||||
var data = {
|
||||
server = DB.Config.MailConfig.Server,
|
||||
auth = DB.Config.MailConfig.Auth,
|
||||
domain = DB.Config.MailConfig.Domain,
|
||||
from = DB.Config.MailConfig.From,
|
||||
to = email.Replace(">","").Replace("\n",""),
|
||||
subject = "Reset your password for CPKG",
|
||||
body = {
|
||||
type = "text/html",
|
||||
data = emailText
|
||||
}
|
||||
};
|
||||
Net.Smtp.Send(data);
|
||||
}
|
||||
func DB.UnforgetPassword(verifyKey, password, confirm)
|
||||
{
|
||||
if(password != confirm) return {Success=false, Reason = "Passwords do not match."};
|
||||
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE verifyKey = {Sqlite.Escape(verifyKey)};");
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
var flags = ParseLong(exec[0].flags);
|
||||
var verifyExpire = ParseLong(exec[0].verifyExpire);
|
||||
var now = DateTime.NowEpoch;
|
||||
|
||||
if((flags & DB.FLAG_RESETPASS) == 0) {
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return {Success=false,Reason="Invalid or expired verification code"};
|
||||
}
|
||||
|
||||
if(now < verifyExpire)
|
||||
{
|
||||
flags &= ~DB.FLAG_VERIFY;
|
||||
flags |= DB.FLAG_VERIFIED;
|
||||
flags &= ~DB.FLAG_RESETPASS;
|
||||
var salt = Crypto.RandomBytes(32, "CPKG");
|
||||
var hash = Crypto.PBKDF2(password, salt, DB.ITTR,64,384);
|
||||
|
||||
Sqlite.Exec(dbCon,$"UPDATE accounts SET flags = {flags}, password_hash = {Sqlite.Escape(Crypto.Base64Encode(hash))}, password_salt = {Sqlite.Escape(Crypto.Base64Encode(salt))} WHERE id = {exec[0].id};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return { Success=true };
|
||||
}
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return {Success=false, Reason="Invalid or expired verification code"};
|
||||
}
|
||||
else {
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
return {Success=false, Reason="Invalid or expired verification code"};
|
||||
}
|
||||
}
|
||||
func DB.ForgotPassword(email)
|
||||
{
|
||||
if(TypeOf(DB.Config.MailConfig) != "Dictionary") return {Success=false, Reason="This server can't send emails"};
|
||||
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE email = {Sqlite.Escape(email)};");
|
||||
var res={Success=false, Reason="Could not find account"};
|
||||
if(TypeOf(exec) != "String" && exec.Length == 1)
|
||||
{
|
||||
Console.WriteLine(exec);
|
||||
var name = exec[0].accountName;
|
||||
|
||||
var flags = ParseLong(exec[0].flags);
|
||||
|
||||
|
||||
var verify_hash = Crypto.RandomBytes(32, "CPKG");
|
||||
var verify_hash_str = Crypto.Base64Encode(verify_hash);
|
||||
|
||||
|
||||
flags |= DB.FLAG_RESETPASS;
|
||||
|
||||
exec = Sqlite.Exec(dbCon,$"UPDATE accounts SET flags = {flags}, verifyKey = {Sqlite.Escape(verify_hash_str)}, verifyExpire = {DateTime.NowEpoch+600} WHERE id = {exec[0].id};");
|
||||
|
||||
if(TypeOf(exec) == "String") {res = {Success = false, Reason = r};}
|
||||
else
|
||||
{
|
||||
if(DB.Config.MailConfig)
|
||||
DB.SendForgotPasswordEmail(email,name, verify_hash_str);
|
||||
|
||||
res = {Success=true, Redirect="/check_email"};
|
||||
}
|
||||
|
||||
|
||||
//DB.FLAG_RESETPASS
|
||||
}
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return res;
|
||||
}
|
||||
func DB.VerifyEmail(verifyKey)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM accounts WHERE verifyKey = {Sqlite.Escape(verifyKey)};");
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
var flags = ParseLong(exec[0].flags);
|
||||
var verifyExpire = ParseLong(exec[0].verifyExpire);
|
||||
var now = DateTime.NowEpoch;
|
||||
|
||||
if((flags & DB.FLAG_RESETPASS) != 0) {
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return {Success=false,Reason="Invalid or expired verification code"};
|
||||
}
|
||||
|
||||
if((flags & DB.FLAG_VERIFIED) != 0) {
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return { Success=true };
|
||||
}
|
||||
|
||||
|
||||
if(now < verifyExpire)
|
||||
{
|
||||
flags &= ~DB.FLAG_VERIFY;
|
||||
flags |= DB.FLAG_VERIFIED;
|
||||
Sqlite.Exec(dbCon,$"UPDATE accounts SET flags = {flags} WHERE id = {exec[0].id};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return { Success=true };
|
||||
}
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return {Success=false, Reason="Invalid or expired verification code"};
|
||||
}
|
||||
else {
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
return {Success=false, Reason="Invalid or expired verification code"};
|
||||
}
|
||||
|
||||
}
|
||||
302
Tesses.CrossLang.PackageServer/src/backend/package.tcross
Normal file
302
Tesses.CrossLang.PackageServer/src/backend/package.tcross
Normal file
@@ -0,0 +1,302 @@
|
||||
func DB.CanUploadPackagePrefix(userId, packageName)
|
||||
{
|
||||
var prefix = packageName.Split(".",true,2);
|
||||
if(prefix.Length >= 1)
|
||||
prefix = prefix[0];
|
||||
else return false;
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon, $"SELECT * FROM reserved_prefixes WHERE prefix = {Sqlite.Escape(prefix)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length > 0) return ParseLong(exec[0].accountId) == userId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
func DB.PackageExists(userId,pkgInfo)
|
||||
{
|
||||
var statusCode = 4;
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * from packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
var pkgId = exec[0].id;
|
||||
if(ParseLong(exec[0].accountId) != userId)
|
||||
statusCode=4;
|
||||
else
|
||||
{
|
||||
exec = Sqlite.Exec(dbCon,$"SELECT * from versions WHERE packageId = {pkgId} AND version = {pkgInfo.Version.VersionInt};");
|
||||
if(TypeOf(exec) == "List")
|
||||
{
|
||||
if(exec.Length == 1)
|
||||
{
|
||||
if(pkgInfo.Version.Stage == "dev")
|
||||
statusCode=3;
|
||||
else
|
||||
statusCode=2;
|
||||
}
|
||||
else statusCode=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else statusCode=0;
|
||||
}
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return statusCode;
|
||||
}
|
||||
func DB.AddPackage(userId,pkgInfo)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
Sqlite.Exec(dbCon,$"INSERT INTO packages (packageName, accountId) VALUES ({Sqlite.Escape(pkgInfo.Name)}, {userId});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
func DB.GetPackageFileData(name, version)
|
||||
{
|
||||
if(TypeOf(name) != "String") name = "";
|
||||
if(TypeOf(version) != "String") version = "";
|
||||
|
||||
var file = DB.working / "Packages" / name / $"{name}-{version}.crvm";
|
||||
|
||||
|
||||
if(FS.Local.FileExists(file) && name.Length > 0 && version.Length > 0)
|
||||
{
|
||||
var strm = FS.Local.OpenFile(file,"rb");
|
||||
|
||||
if(strm != null)
|
||||
{
|
||||
var exec = VM.LoadExecutable(strm);
|
||||
strm.Close();
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.GetPackageIcon(name, version)
|
||||
{
|
||||
var file = DB.GetPackageFileData(name, version);
|
||||
if(file != null)
|
||||
{
|
||||
if(file.Icon != null)
|
||||
{
|
||||
return file.Icon;
|
||||
}
|
||||
}
|
||||
|
||||
return embed("crosslang.png");
|
||||
}
|
||||
func DB.UploadPackage(userId, filePath)
|
||||
{
|
||||
if(!FS.Local.FileExists(filePath)) return {Success=false, Reason = "File does not exist"};
|
||||
var userInfo = DB.GetUserInfo(userId);
|
||||
if(userInfo == null) return { Success=false, Reason = "User does not exist"};
|
||||
|
||||
if((userInfo.flags & DB.FLAG_VERIFIED) == 0) return { Success=false, Reason = "User is not verified"};
|
||||
|
||||
var strm = FS.Local.OpenFile(filePath,"rb");
|
||||
var failed=false;
|
||||
var reason = "";
|
||||
try {
|
||||
var pkgInfo = VM.LoadExecutable(strm);
|
||||
}catch(ex) {
|
||||
if(ex.Type == "NativeException")
|
||||
reason = ex.Text;
|
||||
|
||||
failed=true;
|
||||
}
|
||||
|
||||
strm.Close();
|
||||
if(failed) return {Success=false, Reason = reason};
|
||||
if(!DB.CanUploadPackagePrefix(userId,pkgInfo.Name)) return { Success = false, Reason = "You can't upload a package with that prefix."};
|
||||
|
||||
switch(DB.PackageExists(userId, pkgInfo))
|
||||
{
|
||||
case 0:
|
||||
//package name does not exist
|
||||
DB.AddPackage(userId,pkgInfo);
|
||||
case 1:
|
||||
DB.AddVersion(pkgInfo);
|
||||
FS.Local.CreateDirectory(DB.working / "Packages" / pkgInfo.Name);
|
||||
|
||||
FS.Local.MoveFile(filePath, DB.working / "Packages" / pkgInfo.Name / $"{pkgInfo.Name}-{pkgInfo.Version}.crvm");
|
||||
|
||||
|
||||
//package version does not exist
|
||||
break;
|
||||
case 2:
|
||||
return { Success = false, Reason = "Package already exists and is not a dev package." };
|
||||
case 3:
|
||||
//update package version (it exists but is dev)
|
||||
|
||||
DB.UpdateVersion(pkgInfo);
|
||||
FS.Local.MoveFile(filePath, DB.working / "Packages" / pkgInfo.Name / $"{pkgInfo.Name}-{pkgInfo.Version}.crvm");
|
||||
break;
|
||||
case 4:
|
||||
//package is not yours
|
||||
return { Success = false, Reason = "You don't own the package."};
|
||||
}
|
||||
|
||||
return {Success=true};
|
||||
}
|
||||
func DB.QueryPackages(q, offset, limit,$account)
|
||||
{
|
||||
if(TypeOf(offset) != "Long") offset = 0;
|
||||
if(TypeOf(limit) != "Long") limit = 20;
|
||||
var q2 = Sqlite.Escape($"%{q}%");
|
||||
|
||||
var accountId = -1;
|
||||
|
||||
if(TypeOf(account) == "String")
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, $"SELECT * FROM accounts WHERE accountName = {Sqlite.Escape(account)};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
if(res.Length > 0)
|
||||
{
|
||||
accountId = ParseLong(res[0].id);
|
||||
}
|
||||
else {
|
||||
accountId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var sql = accountId > -1 ? $"SELECT * FROM packages p inner join versions v on p.id = v.packageId and (p.packageName LIKE {q2} OR v.description LIKE {q2}) and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId) INNER JOIN accounts a on a.id = p.accountId WHERE p.accountId == {accountId} LIMIT {limit} OFFSET {offset};" : $"SELECT * FROM packages p inner join versions v on p.id = v.packageId and (p.packageName LIKE {q2} OR v.description LIKE {q2}) and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId) INNER JOIN accounts a on a.id = p.accountId LIMIT {limit} OFFSET {offset};";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
var res2=[];
|
||||
each(var item : res)
|
||||
{
|
||||
var uploadTime = ParseLong(item.uploadTime);
|
||||
res2.Add({
|
||||
accountName = item.accountName,
|
||||
description = item.description,
|
||||
homepage = item.homepage,
|
||||
license = item.license,
|
||||
maintainer = item.maintainer,
|
||||
packageName = item.packageName,
|
||||
uploadTime,
|
||||
uploadDate = new DateTime(uploadTime).ToString("%Y/%m/%d %H:%M:%S UTC"),
|
||||
repo = item.repo,
|
||||
type = item.type,
|
||||
version = Version.FromLong(ParseLong(item.version)).ToString()
|
||||
});
|
||||
}
|
||||
return res2;
|
||||
}
|
||||
|
||||
func DB.GetPackages($page)
|
||||
{
|
||||
if(TypeOf(page) != "Long") page = 1;
|
||||
|
||||
var sql = "SELECT * FROM packages p join versions v on p.id = v.packageId and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId);";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
var res2 = [];
|
||||
each(var item : res)
|
||||
{
|
||||
res2.Add({
|
||||
id = item.packageId,
|
||||
name = item.packageName,
|
||||
version = Version.FromLong(ParseLong(item.version)).ToString(),
|
||||
homepage = item.homepage,
|
||||
repo = item.repo,
|
||||
type = item.type,
|
||||
maintainer = item.maintainer,
|
||||
description = item.description
|
||||
});
|
||||
}
|
||||
return res2;
|
||||
}
|
||||
func DB.RemovePrefix(userName, prefix)
|
||||
{
|
||||
|
||||
if(TypeOf(prefix) != "String" || prefix.Length == 0) return {Success=false, Reason="Invalid prefix"};
|
||||
var user = DB.GetAccountInfo(userName);
|
||||
if(TypeOf(user) != "Dictionary") return {Success=false, Reason = "Username not found"};
|
||||
if((user.flags & DB.FLAG_VERIFIED) == 0) return {Sucess=false, Reason="Account is not verified"};
|
||||
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"DELETE FROM reserved_prefixes WHERE accountId == {user.id} AND prefix == {Sqlite.Escape(prefix)};");
|
||||
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "String") return {Success = false, Reason = exec};
|
||||
|
||||
return {Success=true};
|
||||
}
|
||||
func DB.CreatePrefix(userName, prefix)
|
||||
{
|
||||
if(TypeOf(prefix) != "String" || prefix.Length == 0) return {Success=false, Reason="Invalid prefix"};
|
||||
var user = DB.GetAccountInfo(userName);
|
||||
if(TypeOf(user) != "Dictionary") return {Success=false, Reason = "Username not found"};
|
||||
if((user.flags & DB.FLAG_VERIFIED) == 0) return {Sucess=false, Reason="Account is not verified"};
|
||||
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"INSERT INTO reserved_prefixes (accountId,prefix) values ({user.id},{Sqlite.Escape(prefix)});");
|
||||
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "String") return {Success = false, Reason = exec};
|
||||
|
||||
return {Success=true};
|
||||
}
|
||||
|
||||
func DB.QueryReservedPrefixes(name)
|
||||
{
|
||||
var user = DB.GetAccountInfo(name);
|
||||
if(TypeOf(user) != "Dictionary") return {Success=false, Reason = "Username not found"};
|
||||
|
||||
DB.Lock();
|
||||
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon, $"SELECT * FROM reserved_prefixes WHERE accountId == {user.id};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
|
||||
DB.Unlock();
|
||||
if(TypeOf(exec) == "String") return {
|
||||
Success=false,
|
||||
Reason=exec
|
||||
};
|
||||
|
||||
var items = [];
|
||||
each(var item : exec)
|
||||
{
|
||||
items.Add(item.prefix);
|
||||
}
|
||||
|
||||
return {
|
||||
Success=true,
|
||||
Items = items
|
||||
};
|
||||
}
|
||||
122
Tesses.CrossLang.PackageServer/src/backend/packageversion.tcross
Normal file
122
Tesses.CrossLang.PackageServer/src/backend/packageversion.tcross
Normal file
@@ -0,0 +1,122 @@
|
||||
func DB.GetLatestVersion(name)
|
||||
{
|
||||
var sql = $"SELECT * FROM packages p join versions v on p.id = v.packageId and v.version = (SELECT MAX(version) FROM versions WHERE packageId = v.packageId) and p.packageName = {Sqlite.Escape(name)};";
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(res) == "List" && res.Length > 0)
|
||||
{
|
||||
return Version.FromLong(ParseLong(res[0].version)).ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.GetPackageVersions(name)
|
||||
{
|
||||
var sql = $"SELECT * FROM packages p inner join versions v on p.id = v.packageId inner join accounts a on p.accountId = a.id WHERE p.packageName = {Sqlite.Escape(name)} ORDER BY v.version DESC;";
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, sql);
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
var list = [];
|
||||
each(var item : res)
|
||||
{
|
||||
var version = Version.FromLong(ParseLong(item.version)).ToString();
|
||||
var uploadTime = ParseLong(item.uploadTime);
|
||||
list.Add({
|
||||
version,
|
||||
download = $"./api/v1/download?name={Net.Http.UrlEncode(name)}&version={Net.Http.UrlEncode(version)}",
|
||||
docs = $"./package_docs?name={Net.Http.UrlEncode(name)}&version={Net.Http.UrlEncode(version)}",
|
||||
accountName = item.accountName,
|
||||
description = item.description,
|
||||
maintainer = item.maintainer,
|
||||
type = item.type,
|
||||
repo = item.repo,
|
||||
homepage = item.homepage,
|
||||
license = item.license,
|
||||
uploadTime,
|
||||
uploadDate=new DateTime(uploadTime).ToString("%Y/%m/%d %H:%M:%S UTC")
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
func DB.UpdateVersion(pkgInfo)
|
||||
{
|
||||
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
var pkgId = 0;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
pkgId = exec[0].id;
|
||||
}
|
||||
var version = pkgInfo.Version.VersionInt;
|
||||
var info = Json.Decode(pkgInfo.Info);
|
||||
var description = info.description;
|
||||
var type = info.type;
|
||||
var maintainer = info.maintainer;
|
||||
var homepage = info.homepage;
|
||||
var repo = info.repo;
|
||||
var license = info.license;
|
||||
if(TypeOf(description) != "String") description="";
|
||||
|
||||
if(TypeOf(type) != "String") type="";
|
||||
|
||||
if(TypeOf(maintainer) != "String") maintainer="";
|
||||
|
||||
if(TypeOf(homepage) != "String") homepage="";
|
||||
|
||||
if(TypeOf(repo) != "String") repo="";
|
||||
|
||||
if(TypeOf(license) != "String") license="";
|
||||
|
||||
//CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT);
|
||||
//VALUES ({pkgId},{version},{Sqlite.Escape(description)},{Sqlite.Escape(type)},{Sqlite.Escape(maintainer)},{Sqlite.Escape(homepage)},{Sqlite.Escape(repo)},{Sqlite.Escape(license)});
|
||||
Sqlite.Exec(dbCon,$"UPDATE versions SET description = {Sqlite.Escape(description)}, type = {Sqlite.Escape(type)}, maintainer = {Sqlite.Escape(maintainer)}, homepage = {Sqlite.Escape(homepage)}, repo = {Sqlite.Escape(repo)}, license = {Sqlite.Escape(license)}, uploadTime = {DateTime.NowEpoch} WHERE packageId = {pkgId} AND version = {version};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
func DB.AddVersion(pkgInfo)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM packages WHERE packageName = {Sqlite.Escape(pkgInfo.Name)};");
|
||||
var pkgId = 0;
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1)
|
||||
{
|
||||
pkgId = exec[0].id;
|
||||
}
|
||||
var version = pkgInfo.Version.VersionInt;
|
||||
var info = Json.Decode(pkgInfo.Info);
|
||||
var description = info.description;
|
||||
var type = info.type;
|
||||
var maintainer = info.maintainer;
|
||||
var homepage = info.homepage;
|
||||
var repo = info.repo;
|
||||
var license = info.license;
|
||||
if(TypeOf(description) != "String") description="";
|
||||
|
||||
if(TypeOf(type) != "String") type="";
|
||||
|
||||
if(TypeOf(maintainer) != "String") maintainer="";
|
||||
|
||||
if(TypeOf(homepage) != "String") homepage="";
|
||||
|
||||
if(TypeOf(repo) != "String") repo="";
|
||||
|
||||
if(TypeOf(license) != "String") license="";
|
||||
|
||||
//CREATE TABLE IF NOT EXISTS versions (id INTEGER PRIMARY KEY AUTOINCREMENT, packageId INTEGER, version INTEGER, description TEXT, type TEXT, maintainer TEXT, homepage TEXT, repo TEXT, license TEXT);
|
||||
|
||||
Sqlite.Exec(dbCon,$"INSERT INTO versions (packageId,version,description,type,maintainer,homepage,repo,license,uploadTime) VALUES ({pkgId},{version},{Sqlite.Escape(description)},{Sqlite.Escape(type)},{Sqlite.Escape(maintainer)},{Sqlite.Escape(homepage)},{Sqlite.Escape(repo)},{Sqlite.Escape(license)},{DateTime.NowEpoch});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
}
|
||||
72
Tesses.CrossLang.PackageServer/src/backend/session.tcross
Normal file
72
Tesses.CrossLang.PackageServer/src/backend/session.tcross
Normal file
@@ -0,0 +1,72 @@
|
||||
func DB.GetUserIdFromSession(session)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
||||
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
|
||||
if(TypeOf(exec) == "List" && exec.Length == 1) return ParseLong(exec[0].accountId);
|
||||
|
||||
return -1;
|
||||
}
|
||||
func DB.GetSessionFromBearer(ctx)
|
||||
{
|
||||
var auth = ctx.RequestHeaders.TryGetFirst("Authorization");
|
||||
if(TypeOf(auth) == "String")
|
||||
{
|
||||
auth=auth.Split(" ",true,2);
|
||||
if(auth.Length < 2) return null;
|
||||
if(auth[0] != "Bearer") return null;
|
||||
var uid = DB.GetUserIdFromSession(auth[1]);
|
||||
if(uid != -1) return auth[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.GetSession(ctx)
|
||||
{
|
||||
var cookie = ctx.RequestHeaders.TryGetFirst("Cookie");
|
||||
if(TypeOf(cookie) == "String")
|
||||
{
|
||||
each(var part : cookie.Split("; "))
|
||||
{
|
||||
if(part.Length > 0)
|
||||
{
|
||||
var cookieKV = part.Split("=",true,2);
|
||||
if(cookieKV.Length == 2 && cookieKV[0] == "Session")
|
||||
{
|
||||
var session = cookieKV[1];
|
||||
var sessionId = DB.GetUserIdFromSession(session);
|
||||
|
||||
if(sessionId != -1)
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
func DB.CreateSession(userId)
|
||||
{
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
|
||||
var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG")));
|
||||
Sqlite.Exec(dbCon, $"INSERT INTO sessions (accountId,key) VALUES ({userId},{Sqlite.Escape(rand)});");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
return rand;
|
||||
}
|
||||
func DB.DestroySession(session)
|
||||
{
|
||||
if(TypeOf(session) != "String") return false;
|
||||
DB.Lock();
|
||||
var dbCon = DB.Open();
|
||||
var res = Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};");
|
||||
Sqlite.Close(dbCon);
|
||||
DB.Unlock();
|
||||
if(TypeOf(res) == "String") return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user