Sun, 18 Apr 2021 21:57:43 GMT

master
大蒟蒻 5 years ago
parent 2563c1ff2a
commit 385110c089

679
.gitignore vendored

@ -0,0 +1,679 @@
appsettings.*.json
# Created by https://www.toptal.com/developers/gitignore/api/aspnetcore,csharp,visualstudio,visualstudiocode,dotnetcore
# Edit at https://www.toptal.com/developers/gitignore?templates=aspnetcore,csharp,visualstudio,visualstudiocode,dotnetcore
### ASPNETCore ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/
### Csharp ###
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
# User-specific files (MonoDevelop/Xamarin Studio)
# Mono auto generated files
mono_crash.*
# Build results
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
# NUnit
nunit-*.xml
# Build Results of an ATL Project
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_h.h
*.iobj
*.ipdb
*_wpftmp.csproj
# Chutzpah Test files
# Visual C++ cache files
# Visual Studio profiler
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
# Guidance Automation Toolkit
# ReSharper is a .NET coding add-in
# TeamCity is a build add-in
# DotCover is a Code Coverage Tool
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*[.json, .xml, .info]
# Visual Studio code coverage results
# NCrunch
# MightyMoose
# Web workbench (sass)
# Installshield output folder
# DocProject is a documentation generator add-in
# Click-Once directory
# Publish Web Output
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
# NuGet Packages
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
# Microsoft Azure Build Output
# Microsoft Azure Emulator
# Windows Store app package directories and files
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
# RIA/Silverlight projects
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.ndf
# Business Intelligence projects
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
# GhostDoc plugin setting file
# Node.js Tools for Visual Studio
# Visual Studio 6 build log
# Visual Studio 6 workspace options file
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
# Paket dependency manager
# FAKE - F# Make
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
### DotnetCore ###
# .NET Core build folders
bin/
obj/
# Common node modules locations
/node_modules
/wwwroot/node_modules
### VisualStudioCode ###
.vscode/*
!.vscode/tasks.json
!.vscode/launch.json
*.code-workspace
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
### VisualStudio ###
# User-specific files
# User-specific files (MonoDevelop/Xamarin Studio)
# Mono auto generated files
# Build results
# Visual Studio 2015/2017 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot
# Visual Studio 2017 auto generated files
# MSTest test Results
# NUnit
# Build Results of an ATL Project
# Benchmark Results
# .NET Core
# ASP.NET Scaffolding
# StyleCop
# Files built by Visual Studio
# Chutzpah Test files
# Visual C++ cache files
# Visual Studio profiler
# Visual Studio Trace Files
# TFS 2012 Local Workspace
# Guidance Automation Toolkit
# ReSharper is a .NET coding add-in
# TeamCity is a build add-in
# DotCover is a Code Coverage Tool
# AxoCover is a Code Coverage Tool
# Coverlet is a free, cross platform Code Coverage Tool
# Visual Studio code coverage results
# NCrunch
# MightyMoose
# Web workbench (sass)
# Installshield output folder
# DocProject is a documentation generator add-in
# Click-Once directory
# Publish Web Output
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
# NuGet Packages
# NuGet Symbol Packages
# The packages folder can be ignored because of Package Restore
# except build/, which is used as an MSBuild target.
# Uncomment if necessary however generally it will be regenerated when needed
# NuGet v3's project.json files produces more ignorable files
# Microsoft Azure Build Output
# Microsoft Azure Emulator
# Windows Store app package directories and files
# Visual Studio cache files
# files ending in .cache can be ignored
# but keep track of directories ending in .cache
# Others
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
# RIA/Silverlight projects
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
# SQL Server files
# Business Intelligence projects
# Microsoft Fakes
# GhostDoc plugin setting file
# Node.js Tools for Visual Studio
# Visual Studio 6 build log
# Visual Studio 6 workspace options file
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
# Visual Studio LightSwitch build output
# Paket dependency manager
# FAKE - F# Make
# CodeRush personal settings
# Python Tools for Visual Studio (PTVS)
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
# Telerik's JustMock configuration file
# BizTalk build output
# OpenCover UI analysis results
# Azure Stream Analytics local run output
# MSBuild Binary and Structured Log
# NVidia Nsight GPU debugger configuration file
# MFractors (Xamarin productivity tool) working folder
# Local History for Visual Studio
# BeatPulse healthcheck temp database
# Backup folder for Package Reference Convert tool in Visual Studio 2017
# Ionide (cross platform F# VS Code tools) working folder
# Fody - auto-generated XML schema
### VisualStudio Patch ###
# Additional files built by Visual Studio
*.tlog
# End of https://www.toptal.com/developers/gitignore/api/aspnetcore,csharp,visualstudio,visualstudiocode,dotnetcore

@ -0,0 +1,33 @@
using cugoj_ng_server.Models;
using cugoj_ng_server.Utilities;
using Dapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace cugoj_ng_server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class NewsController : ControllerBase
{
[HttpGet]
[Route("List")]
public IEnumerable<object> List()
{
using var conn = DbConn.GetConnection();
return conn.Query(@"select user_id,title,content from news where defunct='N' order by news_id desc").Select(x => new
{
Author = x.user_id,
Title = x.title,
Content = x.content,
Log = UserModel.Authorization.CanViewAllProblemsAsync("admin")
});
}
}
}

@ -0,0 +1,87 @@
using cugoj_ng_server.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace cugoj_ng_server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProblemController : ControllerBase
{
readonly int problemsPerPage;
readonly int maxSolutionSize;
public ProblemController(IConfiguration configuration)
{
problemsPerPage = configuration.GetValue<int>("Config:ProblemsPerPage");
maxSolutionSize = configuration.GetValue<int>("Config:MaxSolutionSize");
}
[HttpGet]
[Route("List")]
public async Task<object> GetProblemCountAsync()
{
var viewAll = await UserModel.Authorization.CanViewAllProblemsAsync(HttpContext.Session.GetString("user"));
var problemCount = await ProblemModel.GetProblemsCountAsync(viewAll);
var maxPageCount = (problemCount + problemsPerPage - 1) / problemsPerPage;
return new
{
TotalPages = maxPageCount,
ProblemCount = problemCount,
};
}
[HttpGet]
[Route("List/{page}")]
public async Task<object> GetProblemListAsync(int page)
{
if (page <= 0) return BadRequest();
bool viewAll = await UserModel.Authorization.CanViewAllProblemsAsync(HttpContext.Session.GetString("user"));
int maxPageCount = (await ProblemModel.GetProblemsCountAsync(viewAll) + problemsPerPage - 1) / problemsPerPage;
if (page > maxPageCount) return NotFound("I don't have so many problems...");
return new
{
TotalPages = maxPageCount,
ProblemList = await ProblemModel.GetProblemListAsync((page - 1) * problemsPerPage, problemsPerPage, viewAll),
};
}
[HttpGet]
[Route("{pid}")]
public async Task<IActionResult> GetProblemAsync(int pid)
{
bool viewAll = await UserModel.Authorization.CanViewAllProblemsAsync(HttpContext.Session.GetString("user"));
if (!viewAll)
if (await ProblemModel.IsProblemRestrictedAsync(pid))
return StatusCode(StatusCodes.Status403Forbidden, "This problem is private now.");
var problem = await ProblemModel.GetProblemAsync(pid);
if (problem is null) return NotFound("No such problem.");
return Ok(problem);
}
[RequestSizeLimit(1 << 20)]
[HttpPost]
[Route("Submit/{pid}")]
public async Task<IActionResult> SubmitSolutionAsync(int pid, [FromForm] string lang, [FromForm] string code)
{
var user = HttpContext.Session.GetString("user");
if (user is null) return Unauthorized("Not logged in.");
if (code.Length > maxSolutionSize)
return StatusCode(StatusCodes.Status413PayloadTooLarge,
$"Solution size should be less than {maxSolutionSize} bytes.");
if (!SolutionModel.LangMap.ContainsKey(lang)) return BadRequest("No such language.");
var viewAll = await UserModel.Authorization.CanViewAllProblemsAsync(user);
if (!viewAll)
if (await ProblemModel.IsProblemRestrictedAsync(pid))
return StatusCode(StatusCodes.Status403Forbidden, "This problem is private now.");
if (!await ProblemModel.IsProblemExists(pid)) return NotFound("No such problem.");
var submit_id = await SolutionModel.SubmitProblemAsync(user, pid, SolutionModel.LangMap[lang], code);
return Ok(submit_id);
}
}
}

@ -0,0 +1,60 @@
using cugoj_ng_server.Models;
using cugoj_ng_server.Utilities;
using Dapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace cugoj_ng_server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
[HttpPost]
[Route("Login")]
public async Task<IActionResult> LoginAsync([FromForm] string username, [FromForm] string password)
{
var curTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
var lastTry = HttpContext.Session.Get("LastTryLogin")?.Decode<long>() ?? 0;
HttpContext.Session.Set("LastTryLogin", curTimestamp.Encode());
if (curTimestamp - lastTry < 5)
return StatusCode(StatusCodes.Status429TooManyRequests, "Too Many Requests, wait for 5 seconds.");
var res = await UserModel.Authentication.LoginAsync(username, password);
switch (res)
{
case UserModel.Authentication.LoginResult.Success:
HttpContext.Session.SetString("user", username);
return Ok("Logged in");
case UserModel.Authentication.LoginResult.NotExist:
return Unauthorized("User not exist");
case UserModel.Authentication.LoginResult.WrongPassword:
return Unauthorized("Password not correct");
case UserModel.Authentication.LoginResult.Banned:
return StatusCode(StatusCodes.Status403Forbidden, "You are banned");
}
return BadRequest();
}
[Route("Logout")]
public void Logout() => HttpContext.Session.Clear();
[Route("WhoAmI")]
public object WhoAmI()
{
var user = HttpContext.Session.GetString("user");
if (user is null) return new { user };
return new
{
user,
privileges = UserModel.Authorization.GetPrivilegesAsync(user)
};
}
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using StackExchange.Redis;
namespace cugoj_ng_server.Models
{
public class DbConn
{
public static Func<IDbConnection> GetConnection { get; private set; }
public static IConnectionMultiplexer ConnectionMultiplexer { get; private set; }
}
}

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
namespace cugoj_ng_server.Models
{
public class ProblemModel : DbConn
{
const string privateProblemsFilter = "where problem_id not in (SELECT problem_id from private_problems)";
public static async Task<int> GetProblemsCountAsync(bool viewAll = false)
{
using var conn = GetConnection();
return await conn.QueryFirstOrDefaultAsync<int>(@"SELECT COUNT(problem_id) from problem " + (viewAll ? "" : privateProblemsFilter));
}
public static async Task<IEnumerable<dynamic>> GetProblemListAsync(int skip, int limit, bool viewAll = false)
{
using var conn = GetConnection();
return await conn.QueryAsync(
@"SELECT problem_id,title,source,submit,accepted from problem " +
(viewAll ? "" : privateProblemsFilter) + @"limit @skip,@limit",
new { skip, limit }
);
}
public static async Task<dynamic> GetProblemAsync(int pid)
{
using var conn = GetConnection();
return await conn.QueryFirstOrDefaultAsync(@"SELECT * FROM problem where problem_id=@pid", new { pid });
}
public static async Task<bool> IsProblemRestrictedAsync(int pid)
{
using var conn = GetConnection();
return await conn.QueryFirstOrDefaultAsync<int>(@"select count(problem_id) from private_problems where problem_id=@id", new { id = pid }) > 0;
}
public static async Task<bool> IsProblemExists(int pid)
{
using var conn = GetConnection();
return await conn.QueryFirstOrDefaultAsync<int>(@"select count(problem_id) from problem where problem_id=@id", new { id = pid }) > 0;
}
}
}

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using cugoj_ng_server.Utilities;
using Dapper;
namespace cugoj_ng_server.Models
{
public class SolutionModel : DbConn
{
public enum Language
{
C,
CPP,
Java,
Python
}
public static readonly Dictionary<string, Language> LangMap = new();
static SolutionModel()
{
foreach (var lang in Enum.GetValues<Language>())
LangMap.Add(Enum.GetName(lang), lang);
}
public static async Task<int> SubmitProblemAsync(string user, int pid, Language lang, string code)
{
using var conn = GetConnection();
var langid = HUSTOJ.MapLanguageToId(Enum.GetName(lang));
var submit_id = await conn.QueryFirstAsync<int>(@"INSERT INTO solution(problem_id,user_id,in_date,language,ip,code_length,result)
VALUES(@pid,@uid,now(),@lang,'0.0.0.0',@len,@status);
SELECT LAST_INSERT_ID();", new
{
pid,
uid = user,
lang = langid,
len = code.Length,
status = HUSTOJ.Status.MSG_Other
});
var insert_1 = conn.ExecuteAsync(@"INSERT INTO `source_code`(`solution_id`,`source`) VALUES (@sid,@code)", new { sid = submit_id, code });
// I don't know why there's 2 tables, just make hustoj happy...
var insert_2 = conn.ExecuteAsync(@"INSERT INTO `source_code_user`(`solution_id`,`source`) VALUES (@sid,@code)", new { sid = submit_id, code });
await Task.WhenAll(insert_1, insert_2);
await conn.ExecuteAsync(@"UPDATE solution SET result=0 WHERE solution_id=@sid", new { sid = submit_id });
return submit_id;
}
}
}

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using cugoj_ng_server.Utilities;
using Dapper;
namespace cugoj_ng_server.Models
{
public class UserModel : DbConn
{
public class Authentication
{
public enum LoginResult
{
Success,
NotExist,
WrongPassword,
Banned,
}
public static async Task<LoginResult> LoginAsync(string username, string password)
{
using var conn = GetConnection();
var res = await conn.QueryFirstOrDefaultAsync<(
string user,
string password,
string defunct
)>(@"select user_id,password,defunct from users where user_id=@id", new { id = username });
if (res.user == null)
return LoginResult.NotExist;
if (res.defunct == "Y")
return LoginResult.Banned;
if (!HUSTOJ.CheckPw(password, res.password))
return LoginResult.WrongPassword;
return LoginResult.Success;
}
}
public class Authorization
{
public static async Task<bool> CanViewAllProblemsAsync(string user_id)
{
if (user_id == null) return false;
using var conn = GetConnection();
return await conn.QueryFirstOrDefaultAsync<int>(
@"SELECT count(DISTINCT rightstr) FROM privilege
where user_id=@id and rightstr in ('administrator','contest_creator')",
new { id = user_id }) > 0;
}
public static async Task<string[]> GetPrivilegesAsync(string user_id)
{
if (string.IsNullOrEmpty(user_id)) return null;
using var conn = GetConnection();
return (await conn.QueryAsync<string>(@"select rightstr from privilege where user_id=@id and length(rightstr)>5", new { id = user_id })).ToArray();
}
}
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace cugoj_ng_server
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"cugoj_ng_server": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchUrl": "",
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace cugoj_ng_server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var redisConnstr = Configuration.GetConnectionString("redis");
var mysqlConnstr = Configuration.GetConnectionString("mysql");
var sessionTimeout = Configuration.GetValue<int>("Config:SessionTimeout");
services.AddStackExchangeRedisCache(opt =>
{
opt.Configuration = redisConnstr;
opt.InstanceName = "CUGOJ$";
});
services.AddSession(opt =>
{
opt.Cookie.Name = "_SESSION";
opt.Cookie.IsEssential = true;
opt.IdleTimeout = TimeSpan.FromMinutes(sessionTimeout);
});
Utilities.Inject.SetPropertiesByType(typeof(Models.DbConn), null, new()
{
{ typeof(IConnectionMultiplexer), ConnectionMultiplexer.Connect(redisConnstr) },
{ typeof(Func<IDbConnection>), new Func<IDbConnection>(() => new MySql.Data.MySqlClient.MySqlConnection(mysqlConnstr)) },
});
services.AddControllers().AddJsonOptions(opt =>
{
opt.JsonSerializerOptions.IncludeFields = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace cugoj_ng_server.Utilities
{
public static class Crypto
{
public static byte[] SHA1(byte[] data)
{
using var sha1 = System.Security.Cryptography.SHA1.Create();
return sha1.ComputeHash(data);
}
public static byte[] MD5(byte[] data)
{
using var sha1 = System.Security.Cryptography.MD5.Create();
return sha1.ComputeHash(data);
}
}
}

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace cugoj_ng_server.Utilities
{
public static class EncodingExtensions
{
public static byte[] Base64Decode(this string str) => Convert.FromBase64String(str);
public static string Base64Encode(this byte[] data) => Convert.ToBase64String(data);
public static byte[] HexDecode(this string str) => Convert.FromBase64String(str);
public static string HexEncode(this byte[] data) => BitConverter.ToString(data).Replace("-", "").ToLower();
public static byte[] Encode(this string str, Encoding encoding = null) => (encoding ?? Encoding.Default).GetBytes(str);
public static string Decode(this byte[] data, Encoding encoding = null) => (encoding ?? Encoding.Default).GetString(data);
public static byte[] Encode<T>(this T value) where T : struct
{
var arr = new byte[Marshal.SizeOf(value)];
MemoryMarshal.Write(arr, ref value);
return arr;
}
public static T Decode<T>(this byte[] arr) where T : struct
{
return MemoryMarshal.Read<T>(arr);
}
}
}

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace cugoj_ng_server.Utilities
{
using static Crypto;
using static Sequence;
public static class HUSTOJ
{
static readonly Dictionary<string, int> langMap = new();
public enum Langs
{
C, CPP, Pascal, Java, Ruby, Bash, Python, PHP, Perl, CSharp, ObjC, FreeBasic, Scheme, Clang, ClangPP, Lua, JavaScript, Go, Other
};
public enum Status
{
MSG_Pending,
MSG_Pending_Rejudging,
MSG_Compiling,
MSG_Running_Judging,
MSG_Accepted,
MSG_Presentation_Error,
MSG_Wrong_Answer,
MSG_Time_Limit_Exceed,
MSG_Memory_Limit_Exceed,
MSG_Output_Limit_Exceed,
MSG_Runtime_Error,
MSG_Compile_Error,
MSG_Compile_OK,
MSG_TEST_RUN,
MSG_Other
}
static HUSTOJ()
{
foreach (var lang in Enum.GetValues<Langs>())
langMap.Add(Enum.GetName(lang), (int)lang);
}
public static bool CheckPw(string password, string saved)
{
/*
function pwCheck($password,$saved)
{
$svd=base64_decode($saved);
$salt=substr($svd,20);
if(!isOldPW($password)) $password=md5($password);
$hash = base64_encode( sha1(($password) . $salt, true) . $salt );
if (strcmp($hash,$saved)==0) return True;
else return False;
}
*/
ReadOnlySpan<byte> pswdBytes = saved.Base64Decode();
if (pswdBytes.Length != 24) return false;
ReadOnlySpan<byte> finalHash = SHA1(ByteArrayConcat(MD5(password.Encode()).HexEncode().Encode(), pswdBytes[20..].ToArray()));
if (!pswdBytes[..20].SequenceEqual(finalHash)) return false;
return true;
}
public static int MapLanguageToId(string lang) => langMap[lang];
}
}

@ -0,0 +1,23 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace cugoj_ng_server.Utilities
{
public static class Inject
{
const BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
public static void SetPropertiesByType(Type type, object obj, Dictionary<Type, object> rules, BindingFlags bindingFlags = bindingAttr)
{
Array.ForEach(type.GetProperties(bindingFlags), propInfo =>
{
if (rules.TryGetValue(propInfo.PropertyType, out object propValue))
propInfo.SetValue(obj, propValue);
});
}
}
}

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace cugoj_ng_server.Utilities
{
public static class Sequence
{
public static byte[] ByteArrayConcat(params byte[][] arrays)
{
var dstArr = new byte[arrays.Sum(x => x.Length)];
var offset = 0;
Array.ForEach(arrays, arr =>
{
Buffer.BlockCopy(arr, 0, dstArr, offset, arr.Length);
offset += arr.Length;
});
return dstArr;
}
}
}

@ -0,0 +1,14 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Config": {
"SessionTimeout": 1440,
"ProblemsPerPage": 100
}
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>cugoj_ng_server</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.1" />
<PackageReference Include="MySql.Data" Version="8.0.23" />
</ItemGroup>
</Project>

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31112.23
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cugoj-ng-server", "cugoj-ng-server.csproj", "{ED9CA154-9750-4E44-941C-52F9C28148C8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ED9CA154-9750-4E44-941C-52F9C28148C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED9CA154-9750-4E44-941C-52F9C28148C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED9CA154-9750-4E44-941C-52F9C28148C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED9CA154-9750-4E44-941C-52F9C28148C8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7FD2509E-83B7-4FDF-A304-4EBE38755576}
EndGlobalSection
EndGlobal
Loading…
Cancel
Save