All checks were successful
Build and Deploy on Tag / build-crosslang-shell-and-cpkg (push) Successful in 37s
689 lines
25 KiB
Plaintext
689 lines
25 KiB
Plaintext
func main(args)
|
|
{
|
|
|
|
|
|
var dir = ".";
|
|
if(args.Length > 1)
|
|
{
|
|
dir = args[1];
|
|
}
|
|
DB.Init(dir);
|
|
|
|
const timer = new Timer(()=>{
|
|
const time = DateTime.NowEpoch ?? 0;
|
|
DB.Lock();
|
|
const db = DB.Open();
|
|
Sqlite.Exec(db, "DELETE FROM sessions WHERE expires < {time} AND expires > 0;");
|
|
Sqlite.Close(db);
|
|
DB.Unlock();
|
|
},900000);
|
|
|
|
|
|
|
|
/*
|
|
PUT /api/v1/upload Authorization Bearer
|
|
POST /api/v1/login Json object with email and password returns json object with either 200 for success {"token": "TOKEN_VAL"} or non 2XX if fails {"reason": "SOME ERROR"}
|
|
POST /api/v1/logout use Authorization Bearer
|
|
GET /api/v1/latest?name=PackageName returns 200 OK with json {"version":"1.0.0.0-dev"} if it succeeds if it fails returns a failing status code with {"reason": "SOME ERROR"}
|
|
GET /api/v1/download?name=PackageName&version=1.0.0.0-prod returns 200 OK with package bytes or 404 if doesn't exist
|
|
GET /api/v1/search?q=SomeQuery&offset=&limit= returns 200 OK with json of packages {"packages": [{"name": "pkgName","version": "latestVersion", ...}]} or non success status code
|
|
|
|
*/
|
|
|
|
|
|
Net.Http.ListenSimpleWithLoop((ctx)=>{
|
|
if(ctx.Path == "/check_email")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.CheckEmail(ctx));
|
|
}
|
|
if(ctx.Path == "/reserved_prefixes")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.ReservedPrefixes(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/admin")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Admin(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/admin_register")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.AdminRegister(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/admin_accounts")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.AdminAccount(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/package")
|
|
{
|
|
var name = ctx.QueryParams.TryGetFirst("name");
|
|
if(TypeOf(name) != "String") name = "";
|
|
ctx.WithMimeType("text/html").SendText(Pages.Package(ctx,name));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/package_docs")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.PackageDocs(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/packages")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Packages(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/api/v1/latest")
|
|
{
|
|
var name = ctx.QueryParams.TryGetFirst("name");
|
|
if(TypeOf(name) != "String") name = "";
|
|
var version = DB.GetLatestVersion(name);
|
|
if(version != null)
|
|
{
|
|
ctx.WithMimeType("application/json").SendText(Json.Encode({version}));
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/api/v1/search")
|
|
{
|
|
var filter = "";
|
|
var type = ctx.QueryParams.TryGetFirst("type");
|
|
if(TypeOf(type) != "String") type = "";
|
|
var types = type.Length > 0 ? type.Split(",") : [];
|
|
|
|
var pluginHost = ctx.QueryParams.TryGetFirst("pluginHost");
|
|
if(TypeOf(pluginHost) == "String")
|
|
{
|
|
filter += $" AND v.pluginHost = {Sqlite.Escape(pluginHost)}";
|
|
}
|
|
if(types.Length > 0)
|
|
{
|
|
filter += " AND (";
|
|
var first = true;
|
|
each(var item : types)
|
|
{
|
|
if(!first) {
|
|
filter += " OR ";
|
|
}
|
|
filter += $"v.type = {Sqlite.Escape(item)}";
|
|
first=false;
|
|
}
|
|
filter += ")";
|
|
}
|
|
|
|
|
|
var q = ctx.QueryParams.TryGetFirst("q");
|
|
if(TypeOf(q) != "String") q = "";
|
|
var offset = ParseLong(ctx.QueryParams.TryGetFirst("offset"));
|
|
if(TypeOf(offset) != "Long") offset=0;
|
|
var limit = ParseLong(ctx.QueryParams.TryGetFirst("limit"));
|
|
if(TypeOf(limit) != "Long") limit = 20;
|
|
if(limit <= 0) limit = 20;
|
|
|
|
var res = DB.QueryPackages(q, offset*limit, limit, undefined, filter);
|
|
if(TypeOf(res) != "List")
|
|
{
|
|
ctx.StatusCode=500;
|
|
ctx.SendText("Packages not a list");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ctx.WithMimeType("application/json").SendText(Json.Encode({packages=res}));
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/change_motto")
|
|
{
|
|
if(ctx.Method == "POST")
|
|
{
|
|
var motto = ctx.QueryParams.TryGetFirst("motto");
|
|
if(motto == null) motto = "";
|
|
var session = DB.GetSession(ctx);
|
|
if(session == null)
|
|
{
|
|
ctx.StatusCode = 401;
|
|
ctx.SendText("<h1>You are not logged in</h1>");
|
|
return true;
|
|
}
|
|
|
|
var csrf = ctx.QueryParams.TryGetFirst("csrf");
|
|
var result = { Success=false, Reason = "Invalid CSRF"};
|
|
|
|
if(DB.VerifyCSRF(session,csrf))
|
|
{
|
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
|
var url = DB.ChangeMotto(userId,motto);
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", url);
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href={url}>here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if(ctx.Path == "/upload")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Upload(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
if(ctx.NeedToParseFormData)
|
|
{
|
|
var filePath = DB.working / "Temp" / $"{DB.GetUniqueNumber()}.crvm";
|
|
var hasFile=false;
|
|
var strm = FS.Local.OpenFile(filePath,"wb");
|
|
ctx.ParseFormData((mime,filename,name)=>{
|
|
|
|
if(name == "package")
|
|
{
|
|
if(hasFile) return new MemoryStream(true);
|
|
hasFile=true;
|
|
|
|
return strm;
|
|
}
|
|
else
|
|
return new MemoryStream(true);
|
|
});
|
|
|
|
strm.Close();
|
|
|
|
var session = DB.GetSession(ctx);
|
|
if(session == null)
|
|
{
|
|
|
|
if(FS.Local.FileExists(filePath))
|
|
FS.Local.DeleteFile(filePath);
|
|
ctx.StatusCode = 401;
|
|
ctx.SendText("<h1>You are not logged in</h1>");
|
|
return true;
|
|
}
|
|
|
|
var csrf = ctx.QueryParams.TryGetFirst("csrf");
|
|
var result = { Success=false, Reason = "Invalid CSRF"};
|
|
|
|
if(!DB.VerifyCSRF(session,csrf))
|
|
{
|
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
|
result = DB.UploadPackage(userId, filePath);
|
|
}
|
|
|
|
if(FS.Local.FileExists(filePath))
|
|
FS.Local.DeleteFile(filePath);
|
|
|
|
if(result.Success)
|
|
{
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href="./">here</a> if it does not redirect
|
|
</null>);
|
|
}
|
|
else
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText(result.Reason);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
if(ctx.Path == "/api")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.API.Index());
|
|
return true;
|
|
}
|
|
|
|
if(ctx.Path == "/api-v1")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.API.V1());
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/api/v1/versions")
|
|
{
|
|
var name = ctx.QueryParams.TryGetFirst("name");
|
|
if(TypeOf(name) == "String")
|
|
{
|
|
var versions = DB.GetPackageVersions(name);
|
|
ctx.WithMimeType("application/json").SendJson({
|
|
success=true,
|
|
versions
|
|
});
|
|
return true;
|
|
}
|
|
ctx.WithMimeType("application/json").SendJson({
|
|
success=false
|
|
});
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/delete_packages")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.DeletePackages(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
var packages = ctx.QueryParams.TryGetFirst("packages");
|
|
var email = ctx.QueryParams.TryGetFirst("email");
|
|
var password = ctx.QueryParams.TryGetFirst("password");
|
|
var msg = DB.DeletePackages(email,password, packages);
|
|
var html = <div class="container"><h1>{msg}</h1></div>;
|
|
ctx.WithMimeType("text/html").SendText(Shell(msg,[], html));
|
|
}
|
|
}
|
|
if(ctx.Path == "/api/v1/upload")
|
|
{
|
|
if(ctx.Method == "PUT")
|
|
{
|
|
var session = DB.GetSessionFromBearer(ctx);
|
|
if(session == null)
|
|
{
|
|
ctx.StatusCode=401;
|
|
ctx.SendJson({
|
|
reason = "You are not logged in"
|
|
});
|
|
return true;
|
|
}
|
|
var userId = DB.GetUserIdFromSession(session).accountId;
|
|
var filePath = DB.working / "Temp" / $"{DB.GetUniqueNumber()}.crvm";
|
|
|
|
var strm = FS.Local.OpenFile(filePath,"wb");
|
|
|
|
ctx.ReadStream(strm);
|
|
strm.Close();
|
|
var result = DB.UploadPackage(userId, filePath);
|
|
if(result.Success)
|
|
{
|
|
ctx.StatusCode = 204;
|
|
ctx.ResponseHeaders.SetValue("Content-Length","0");
|
|
ctx.WriteHeaders();
|
|
return true;
|
|
}
|
|
else {
|
|
ctx.StatusCode = 400;
|
|
ctx.SendJson({reason = result.Reason});
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
ctx.StatusCode = 400;
|
|
ctx.SendJson({
|
|
reason = $"Expected PUT method got {ctx.Method}"
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/api/v1/login")
|
|
{
|
|
if(ctx.Method == "POST")
|
|
{
|
|
var json = ctx.ReadJson();
|
|
if(TypeOf(json) != "Dictionary" || TypeOf(json.email) != "String" || TypeOf(json.password) != "String") {
|
|
ctx.StatusCode = 400;
|
|
ctx.SendJson({
|
|
reason = "Expected a Json Dictionary, with the email and password"
|
|
});
|
|
return true;
|
|
}
|
|
|
|
var accountId = DB.GetAccountId(json.email, json.password);
|
|
if(accountId == -1)
|
|
{
|
|
ctx.StatusCode = 401;
|
|
|
|
ctx.SendJson({
|
|
reason = "Invalid credentials"
|
|
});
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
ctx.SendJson({
|
|
token = DB.CreateSession(accountId,false, TypeIsString(json.name) ? json.name : "CrossLang Shell")
|
|
});
|
|
return true;
|
|
|
|
|
|
}
|
|
else {
|
|
ctx.StatusCode = 400;
|
|
ctx.SendJson({
|
|
reason = $"Expected POST method got {ctx.Method}"
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/api/v1/package_icon.png")
|
|
{
|
|
var name = ctx.QueryParams.TryGetFirst("name");
|
|
var version = ctx.QueryParams.TryGetFirst("version");
|
|
ctx.ResponseHeaders.SetValue("Content-Type", "image/png");
|
|
ctx.SendBytes(DB.GetPackageIcon(name,version));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/api/v1/download")
|
|
{
|
|
var name = ctx.QueryParams.TryGetFirst("name");
|
|
var version = ctx.QueryParams.TryGetFirst("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)
|
|
{
|
|
ctx.WithMimeType("application/crvm").WithContentDisposition($"{name}-{version}.crvm",false).SendStream(strm);
|
|
strm.Close();
|
|
return true;
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
if(ctx.Path == "/api/v1/logout")
|
|
{
|
|
ctx.WithMimeType("application/json").SendText({
|
|
Success=DB.DestroySession(DB.GetSessionFromBearer(ctx))
|
|
}.ToString());
|
|
}
|
|
if(ctx.Path == "/logout")
|
|
{
|
|
if(DB.DestroySession(DB.GetSession(ctx)))
|
|
{
|
|
ctx.StatusCode = 302;
|
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href="./">here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
else {
|
|
ctx.WithMimeType("text/html").SendText(Shell("Not logged in",[],<h1>Not logged in</h1>));
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/login")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Login(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
|
|
var email = ctx.QueryParams.TryGetFirst("email");
|
|
if(TypeOf(email) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the email buddy</h1>");
|
|
return true;
|
|
}
|
|
var password = ctx.QueryParams.TryGetFirst("password");
|
|
if(TypeOf(password) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the password buddy</h1>");
|
|
return true;
|
|
}
|
|
|
|
var accountId = DB.GetAccountId(email, password);
|
|
if(accountId == -1)
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText(Shell("Invalid credentials",[],"<h1>Invalid credentials</h1>"));
|
|
return true;
|
|
}
|
|
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
|
const browser="Browser";
|
|
const now = DateTime.NowEpoch??0;
|
|
|
|
ctx.ResponseHeaders.SetValue("Set-Cookie", $"Session={DB.CreateSession(accountId,true, browser)}; SameSite=Strict; Expires={new DateTime(now+DB.Expires).ToHttpDate()}");
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href="./">here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/verify")
|
|
{
|
|
var code = ctx.QueryParams.TryGetFirst("code");
|
|
if(TypeOf(code) == "String")
|
|
{
|
|
var res = DB.VerifyEmail(code);
|
|
if(res.Success)
|
|
{
|
|
ctx.StatusCode = 302;
|
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href="./">here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
else {
|
|
ctx.StatusCode=401;
|
|
ctx.WithMimeType("text/html").SendText(Pages.VerificationFailed(res.Reason));
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
ctx.WithMimeType("text/html").SendText(Pages.VerificationFailed("Requires query parameter code"));
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/new_password")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.NewPassword(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
|
|
var code = ctx.QueryParams.TryGetFirst("code");
|
|
var password = ctx.QueryParams.TryGetFirst("password");
|
|
|
|
var confirm = ctx.QueryParams.TryGetFirst("confirm");
|
|
if(TypeOf(code) == "String" && TypeOf(password) == "String" && TypeOf(confirm) == "String")
|
|
{
|
|
var res = DB.UnforgetPassword(code,password,confirm);
|
|
if(res.Success)
|
|
{
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", "/");
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href="./">here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
else {
|
|
ctx.StatusCode=401;
|
|
ctx.WithMimeType("text/html").SendText(Pages.ResetPasswordFailed(res.Reason));
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
ctx.StatusCode = 400;
|
|
ctx.WithMimeType("text/html").SendText(Pages.ResetPasswordFailed("Invalid State"));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if(ctx.Path == "/forgot_password")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.ForgotPassword(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
var email = ctx.QueryParams.TryGetFirst("email");
|
|
if(TypeOf(email) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the email buddy</h1>");
|
|
return true;
|
|
}
|
|
var res = DB.ForgotPassword(email);
|
|
if(!res.Success)
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText($"<h1>Error: {Net.Http.HtmlEncode(res.Reason)}</h1>");
|
|
return true;
|
|
}
|
|
|
|
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href={res.Redirect}>here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/signup")
|
|
{
|
|
if(ctx.Method == "GET")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Signup(ctx));
|
|
return true;
|
|
}
|
|
else if(ctx.Method == "POST")
|
|
{
|
|
var email = ctx.QueryParams.TryGetFirst("email");
|
|
if(TypeOf(email) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the email buddy</h1>");
|
|
return true;
|
|
}
|
|
var displayName = ctx.QueryParams.TryGetFirst("displayName");
|
|
if(TypeOf(displayName) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the displayName buddy</h1>");
|
|
return true;
|
|
}
|
|
var password = ctx.QueryParams.TryGetFirst("password");
|
|
if(TypeOf(password) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the password buddy</h1>");
|
|
return true;
|
|
}
|
|
var passwordconfirm = ctx.QueryParams.TryGetFirst("passwordconfirm");
|
|
if(TypeOf(passwordconfirm) != "String")
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>You forgot the passwordconfirm buddy</h1>");
|
|
return true;
|
|
}
|
|
|
|
if(password != passwordconfirm)
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText("<h1>The passwords do not match</h1>");
|
|
return true;
|
|
}
|
|
|
|
var res = DB.CreateUser(email, displayName, password);
|
|
if(!res.Success)
|
|
{
|
|
ctx.StatusCode = 400;
|
|
ctx.SendText(Shell("Error",[],$"<h1>Error: {Net.Http.HtmlEncode(res.Reason)}</h1>"));
|
|
return true;
|
|
}
|
|
|
|
|
|
ctx.StatusCode = 303;
|
|
ctx.ResponseHeaders.SetValue("Location", res.Redirect);
|
|
ctx.WithMimeType("text/html").SendText(<null>
|
|
<h1>Redirecting</h1>
|
|
Click <a href={res.Redirect}>here</a> if it does not redirect
|
|
</null>);
|
|
return true;
|
|
}
|
|
}
|
|
if(ctx.Path == "/account")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Account(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/sessions")
|
|
{
|
|
|
|
ctx.WithMimeType("text/html").SendText(Pages.Sessions(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/create_session")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.CreateSession(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/session")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Session(ctx));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/css/bootstrap.min.css")
|
|
{
|
|
ctx.WithMimeType("text/css").SendBytes(embed("css/bootstrap.min.css"));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/css/bootstrap.min.css.map")
|
|
{
|
|
ctx.WithMimeType("application/json").SendBytes(embed("css/bootstrap.min.css.map"));
|
|
return true;
|
|
}
|
|
|
|
if(ctx.Path == "/js/bootstrap.min.js")
|
|
{
|
|
ctx.WithMimeType("text/javascript").SendBytes(embed("js/bootstrap.min.js"));
|
|
return true;
|
|
}
|
|
|
|
if(ctx.Path == "/js/bootstrap.min.js.map")
|
|
{
|
|
ctx.WithMimeType("application/json").SendBytes(embed("js/bootstrap.min.js.map"));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/favicon.ico")
|
|
{
|
|
ctx.WithMimeType("image/x-icon").SendBytes(embed("favicon.ico"));
|
|
return true;
|
|
}
|
|
if(ctx.Path == "/")
|
|
{
|
|
ctx.WithMimeType("text/html").SendText(Pages.Index(ctx));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},DB.Port);
|
|
|
|
timer.Callback = null;
|
|
} |