mirror of
https://gitea.tendokyu.moe/Kayori/Medusa.net.git
synced 2026-09-22 22:38:00 +03:00
Init
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
!**/.gitignore
|
||||
!.git/HEAD
|
||||
!.git/config
|
||||
!.git/packed-refs
|
||||
!.git/refs/heads/**
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,visualstudiocode,visualstudio
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,visualstudiocode,visualstudio
|
||||
|
||||
### DotnetCore ###
|
||||
# .NET Core build folders
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Common node modules locations
|
||||
/node_modules
|
||||
/wwwroot/node_modules
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.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
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# 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
|
||||
# Note: 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
|
||||
# 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
|
||||
*.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
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# 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
|
||||
orleans.codegen.cs
|
||||
|
||||
# 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)
|
||||
#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
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
|
||||
# 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/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# 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/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# 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
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
||||
### VisualStudio Patch ###
|
||||
# Additional files built by Visual Studio
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,visualstudiocode,visualstudio
|
||||
/Core/Server/Medusa.db
|
||||
Generated
+13
@@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/projectSettingsUpdater.xml
|
||||
/modules.xml
|
||||
/.idea.Medusa.iml
|
||||
/contentModel.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
Medusa
|
||||
Generated
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Abstractions.Handlers;
|
||||
|
||||
public abstract class Handler
|
||||
{
|
||||
public string HandlerModule { get; set; } = "";
|
||||
public string HandlerMethod { get; set; } = "";
|
||||
public string? HandlerGameCode { get; set; }
|
||||
public string? HandlerMinVer { get; set; }
|
||||
public string? HandlerMaxVer { get; set; }
|
||||
|
||||
public virtual void Configure() { throw new NotImplementedException("Configure method not implemented."); }
|
||||
|
||||
protected void Module(string module)
|
||||
{
|
||||
this.HandlerModule = module;
|
||||
}
|
||||
|
||||
protected void Method(string method)
|
||||
{
|
||||
this.HandlerMethod = method;
|
||||
}
|
||||
|
||||
protected void GameCode(string gameCode)
|
||||
{
|
||||
this.HandlerGameCode = gameCode;
|
||||
}
|
||||
|
||||
protected void MinVer(string minVer)
|
||||
{
|
||||
this.HandlerMinVer = minVer;
|
||||
}
|
||||
|
||||
protected void MaxVer(string maxVer)
|
||||
{
|
||||
this.HandlerMaxVer = maxVer;
|
||||
}
|
||||
|
||||
public virtual XDocument Handle(string model) { throw new NotImplementedException("Handle method not implemented."); }
|
||||
public virtual Task<XDocument> HandleAsync(string model) { throw new NotImplementedException("Handle method not implemented."); }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Abstractions.Handlers
|
||||
{
|
||||
public interface IHandler
|
||||
{
|
||||
Task<XDocument> HandleAsync(string model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.1184077">
|
||||
<PropertyGroup>
|
||||
<StartupCommand>npm run dev</StartupCommand>
|
||||
<JavaScriptTestRoot>.\</JavaScriptTestRoot>
|
||||
<JavaScriptTestFramework>Jest</JavaScriptTestFramework>
|
||||
<!-- Allows the build (or compile) script located on package.json to run on Build -->
|
||||
<ShouldRunBuildScript>false</ShouldRunBuildScript>
|
||||
<!-- Folder where production build objects will be placed -->
|
||||
<BuildOutputFolder>$(MSBuildProjectDirectory)\dist</BuildOutputFolder>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,39 @@
|
||||
# core2.client
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<PackageJsonName Condition="$(PackageJsonName) == ''">client</PackageJsonName>
|
||||
<PackageJsonVersion Condition="$(PackageJsonVersion) == ''">0.0.0</PackageJsonVersion>
|
||||
<PackageJsonPrivate Condition="$(PackageJsonPrivate) == ''">true</PackageJsonPrivate>
|
||||
<PackageJsonType Condition="$(PackageJsonType) == ''">module</PackageJsonType>
|
||||
<PackageJsonScriptsDev Condition="$(PackageJsonScriptsDev) == ''">vite</PackageJsonScriptsDev>
|
||||
<PackageJsonScriptsBuild Condition="$(PackageJsonScriptsBuild) == ''">run-p type-check "build-only {@}" --</PackageJsonScriptsBuild>
|
||||
<PackageJsonScriptsPreview Condition="$(PackageJsonScriptsPreview) == ''">vite preview</PackageJsonScriptsPreview>
|
||||
<PackageJsonScriptsBuildOnly Condition="$(PackageJsonScriptsBuildOnly) == ''">vite build</PackageJsonScriptsBuildOnly>
|
||||
<PackageJsonScriptsTypeCheck Condition="$(PackageJsonScriptsTypeCheck) == ''">vue-tsc --build --force</PackageJsonScriptsTypeCheck>
|
||||
<PackageJsonScriptsLint Condition="$(PackageJsonScriptsLint) == ''">eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore</PackageJsonScriptsLint>
|
||||
<PackageJsonDependenciesVue Condition="$(PackageJsonDependenciesVue) == ''">^3.4.29</PackageJsonDependenciesVue>
|
||||
<PackageJsonDevdependenciesRushstackEslintPatch Condition="$(PackageJsonDevdependenciesRushstackEslintPatch) == ''">^1.8.0</PackageJsonDevdependenciesRushstackEslintPatch>
|
||||
<PackageJsonDevdependenciesTsconfigNode20 Condition="$(PackageJsonDevdependenciesTsconfigNode20) == ''">^20.1.4</PackageJsonDevdependenciesTsconfigNode20>
|
||||
<PackageJsonDevdependenciesTypesNode Condition="$(PackageJsonDevdependenciesTypesNode) == ''">^20.14.5</PackageJsonDevdependenciesTypesNode>
|
||||
<PackageJsonDevdependenciesVitejsPluginVue Condition="$(PackageJsonDevdependenciesVitejsPluginVue) == ''">^5.0.5</PackageJsonDevdependenciesVitejsPluginVue>
|
||||
<PackageJsonDevdependenciesVueEslintConfigTypescript Condition="$(PackageJsonDevdependenciesVueEslintConfigTypescript) == ''">^13.0.0</PackageJsonDevdependenciesVueEslintConfigTypescript>
|
||||
<PackageJsonDevdependenciesVueTsconfig Condition="$(PackageJsonDevdependenciesVueTsconfig) == ''">^0.5.1</PackageJsonDevdependenciesVueTsconfig>
|
||||
<PackageJsonDevdependenciesEslint Condition="$(PackageJsonDevdependenciesEslint) == ''">^8.57.0</PackageJsonDevdependenciesEslint>
|
||||
<PackageJsonDevdependenciesEslintPluginVue Condition="$(PackageJsonDevdependenciesEslintPluginVue) == ''">^9.23.0</PackageJsonDevdependenciesEslintPluginVue>
|
||||
<PackageJsonDevdependenciesNpmRunAll2 Condition="$(PackageJsonDevdependenciesNpmRunAll2) == ''">^6.2.0</PackageJsonDevdependenciesNpmRunAll2>
|
||||
<PackageJsonDevdependenciesTypescript Condition="$(PackageJsonDevdependenciesTypescript) == ''">~5.4.0</PackageJsonDevdependenciesTypescript>
|
||||
<PackageJsonDevdependenciesVite Condition="$(PackageJsonDevdependenciesVite) == ''">^5.3.1</PackageJsonDevdependenciesVite>
|
||||
<PackageJsonDevdependenciesVueTsc Condition="$(PackageJsonDevdependenciesVueTsc) == ''">^2.0.21</PackageJsonDevdependenciesVueTsc>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Generated
+3285
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "client",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/node": "^20.14.5",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
"vue-tsc": "^2.0.21"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import TheWelcome from './components/TheWelcome.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
|
||||
|
||||
<div class="wrapper">
|
||||
<HelloWorld msg="You did it!" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<TheWelcome />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
header {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
padding-right: calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
|
||||
header .wrapper {
|
||||
display: flex;
|
||||
place-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--vt-c-white);
|
||||
--color-background-soft: var(--vt-c-white-soft);
|
||||
--color-background-mute: var(--vt-c-white-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-light-1);
|
||||
--color-text: var(--vt-c-text-light-1);
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: var(--vt-c-black);
|
||||
--color-background-soft: var(--vt-c-black-soft);
|
||||
--color-background-mute: var(--vt-c-black-mute);
|
||||
|
||||
--color-border: var(--vt-c-divider-dark-2);
|
||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||
|
||||
--color-heading: var(--vt-c-text-dark-1);
|
||||
--color-text: var(--vt-c-text-dark-2);
|
||||
}
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
Inter,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
After Width: | Height: | Size: 276 B |
@@ -0,0 +1,35 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="weather-component">
|
||||
<h1>Weather forecast</h1>
|
||||
<p>This component demonstrates fetching data from the server.</p>
|
||||
|
||||
<div v-if="loading" class="loading">
|
||||
Loading... Please refresh once the ASP.NET backend has started. See <a href="https://aka.ms/jspsintegrationvue">https://aka.ms/jspsintegrationvue</a> for more details.
|
||||
</div>
|
||||
|
||||
<div v-if="post" class="content">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="forecast in post" :key="forecast.date">
|
||||
<td>{{ forecast.date }}</td>
|
||||
<td>{{ forecast.temperatureC }}</td>
|
||||
<td>{{ forecast.temperatureF }}</td>
|
||||
<td>{{ forecast.summary }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
type Forecasts = {
|
||||
date: string,
|
||||
temperatureC: string,
|
||||
temperatureF: string,
|
||||
summary: string
|
||||
}[];
|
||||
|
||||
interface Data {
|
||||
loading: boolean,
|
||||
post: null | Forecasts
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
data(): Data {
|
||||
return {
|
||||
loading: false,
|
||||
post: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// fetch the data when the view is created and the data is
|
||||
// already being observed
|
||||
this.fetchData();
|
||||
},
|
||||
watch: {
|
||||
// call again the method if the route changes
|
||||
'$route': 'fetchData'
|
||||
},
|
||||
methods: {
|
||||
fetchData(): void {
|
||||
this.post = null;
|
||||
this.loading = true;
|
||||
|
||||
fetch('weatherforecast')
|
||||
.then(r => r.json())
|
||||
.then(json => {
|
||||
this.post = json as Forecasts;
|
||||
this.loading = false;
|
||||
return;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding-left: .5rem;
|
||||
padding-right: .5rem;
|
||||
}
|
||||
|
||||
.weather-component {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
<script setup lang="ts">
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
import ToolingIcon from './icons/IconTooling.vue'
|
||||
import EcosystemIcon from './icons/IconEcosystem.vue'
|
||||
import CommunityIcon from './icons/IconCommunity.vue'
|
||||
import SupportIcon from './icons/IconSupport.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<ToolingIcon />
|
||||
</template>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
|
||||
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
|
||||
you need to test your components and web pages, check out
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
|
||||
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
|
||||
>Cypress Component Testing</a
|
||||
>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in <code>README.md</code>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
|
||||
Discord server, or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also subscribe to
|
||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
|
||||
the official
|
||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
twitter account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
||||
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,6 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
|
||||
import { defineConfig } from 'vite';
|
||||
import plugin from '@vitejs/plugin-vue';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import child_process from 'child_process';
|
||||
import { env } from 'process';
|
||||
|
||||
const baseFolder =
|
||||
env.APPDATA !== undefined && env.APPDATA !== ''
|
||||
? `${env.APPDATA}/ASP.NET/https`
|
||||
: `${env.HOME}/.aspnet/https`;
|
||||
|
||||
fs.mkdirSync(baseFolder, { recursive: true });
|
||||
|
||||
const certificateName = "core2.client";
|
||||
const certFilePath = path.join(baseFolder, `${certificateName}.pem`);
|
||||
const keyFilePath = path.join(baseFolder, `${certificateName}.key`);
|
||||
|
||||
if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
|
||||
if (0 !== child_process.spawnSync('dotnet', [
|
||||
'dev-certs',
|
||||
'https',
|
||||
'--export-path',
|
||||
certFilePath,
|
||||
'--format',
|
||||
'Pem',
|
||||
'--no-password',
|
||||
], { stdio: 'inherit', }).status) {
|
||||
throw new Error("Could not create certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
|
||||
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'https://localhost:7059';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [plugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'^/weatherforecast': {
|
||||
target,
|
||||
secure: false
|
||||
}
|
||||
},
|
||||
port: 5173,
|
||||
https: {
|
||||
key: fs.readFileSync(keyFilePath),
|
||||
cert: fs.readFileSync(certFilePath),
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "8.0.8",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Server.Entities;
|
||||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
: IdentityDbContext<User, IdentityRole<int>, int>(options)
|
||||
{
|
||||
public override DbSet<User> Users { get; set; }
|
||||
public DbSet<Card> Cards { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<User>()
|
||||
.HasMany(u => u.Cards)
|
||||
.WithOne(c => c.User)
|
||||
.HasForeignKey(c => c.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
base.OnModelCreating(builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Server.Attributes;
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class HandlerAttribute(string module, string method) : Attribute
|
||||
{
|
||||
public readonly string Module = module;
|
||||
public readonly string Method = method;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Server.Entities
|
||||
{
|
||||
public class Card
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
public required string KonamiId { get; set; }
|
||||
public required string RawId { get; set; }
|
||||
public int UserId { get; set; }
|
||||
public User User { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Server.Entities
|
||||
{
|
||||
public class User: IdentityUser<int>
|
||||
{
|
||||
public int PaseliAmount { get; set; } = 0;
|
||||
public required int Pin { get; set; }
|
||||
|
||||
public List<Card> Cards { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Server.Handlers;
|
||||
using Server.Services;
|
||||
using System.Reflection;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Extensions;
|
||||
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseHandlers(this IApplicationBuilder app)
|
||||
{
|
||||
var handlerService = app.ApplicationServices.GetRequiredService<IHandlerService>();
|
||||
|
||||
var assembly = Assembly.GetEntryAssembly() ?? throw new InvalidOperationException("Could not find entry assembly.");
|
||||
var types = assembly.GetTypes().Where(a => a.GetInterfaces().Contains(typeof(IHandler)) ||
|
||||
(a.IsSubclassOf(typeof(Handler)) && !a.IsAbstract));
|
||||
|
||||
handlerService.Handlers.AddRange(types);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Server.Services;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Server.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Add handler service to DI
|
||||
/// </summary>
|
||||
/// <param name="services">The extended IServiceCollection</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddHandlers(this IServiceCollection services)
|
||||
{
|
||||
services.Add(new ServiceDescriptor(typeof(IHandlerService), typeof(HandlerService), ServiceLifetime.Singleton));
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services implementing an interface to the DI container.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The interface type</typeparam>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddIServicesWithType<TType>(this IServiceCollection serviceCollection,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
var assembly = typeof(TType).Assembly;
|
||||
var types = assembly.DefinedTypes
|
||||
.Where(x => typeof(TType).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
|
||||
.ToArray();
|
||||
|
||||
if(types.Length == 0) return serviceCollection;
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(typeof(TType), type.AsType(), lifetime));
|
||||
}
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services from a namespace that implement an interface to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="interfaceNamespace">The namespace of the interfaces</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddServicesInNamespaceWithInterface(this IServiceCollection serviceCollection,
|
||||
string interfaceNamespace, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var foundAssembly = assemblies.FirstOrDefault(x => x.DefinedTypes.Any(typeInfo => typeInfo.Namespace?.Equals(interfaceNamespace) ?? false));
|
||||
|
||||
if(foundAssembly == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var loaded = Assembly.Load(interfaceNamespace.Split('.')[0]);
|
||||
foundAssembly = loaded;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
var types = foundAssembly.DefinedTypes
|
||||
.Where(x => x.Namespace == interfaceNamespace && !x.IsInterface && !x.IsAbstract && !x.ContainsGenericParameters && !x.IsNested)
|
||||
.ToList();
|
||||
|
||||
if(types.Count == 0) return serviceCollection;
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
var interfaceType = type.GetInterfaces().FirstOrDefault();
|
||||
if(interfaceType != null)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(interfaceType, type.AsType(), lifetime));
|
||||
}
|
||||
}
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services from multiple namespaces to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="namespaces">List of namespaces</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddServicesInNamespaces(this IServiceCollection serviceCollection,
|
||||
string[] namespaces, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var foundAssemblies = assemblies
|
||||
.Where(a => a.DefinedTypes.Any(t => namespaces.Contains(t.Namespace)))
|
||||
.ToList();
|
||||
|
||||
var notFoundNamespaces = namespaces.Except(foundAssemblies.SelectMany(a => a.GetTypes().Select(t => t.Namespace))).ToList();
|
||||
var types = new List<TypeInfo>();
|
||||
|
||||
foreach(var assembly in foundAssemblies)
|
||||
{
|
||||
var foundTypes = assembly.DefinedTypes
|
||||
.Where(x => namespaces.Contains(x.Namespace) && !x.IsInterface && !x.IsAbstract && !x.IsNested)
|
||||
.ToArray();
|
||||
types.AddRange(foundTypes);
|
||||
}
|
||||
|
||||
foreach(var notFound in notFoundNamespaces)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assemblyName = notFound?.Split('.')[0];
|
||||
var assembly = Assembly.Load(assemblyName ?? "");
|
||||
var foundTypes = assembly.DefinedTypes
|
||||
.Where(x => x.Namespace == notFound && !x.IsInterface && !x.IsAbstract && !x.IsNested)
|
||||
.ToArray();
|
||||
types.AddRange(foundTypes);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
if(types.Count == 0) return serviceCollection;
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime));
|
||||
}
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services from a single namespace to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="namespace">The namespace to scan</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddServicesInNamespace(this IServiceCollection serviceCollection,
|
||||
string @namespace, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var assembly = assemblies.FirstOrDefault(x => x.DefinedTypes.Any(typeInfo => typeInfo.Namespace == @namespace));
|
||||
|
||||
var types = assembly?.DefinedTypes
|
||||
.Where(x => x.Namespace == @namespace && !x.IsInterface && !x.IsAbstract && !x.IsNested)
|
||||
.ToArray();
|
||||
|
||||
if(types == null || types.Length == 0) return serviceCollection;
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime));
|
||||
}
|
||||
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a single class as a service to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="serviceClassType">The class type to add</param>
|
||||
/// <param name="lifetime">The lifetime of the service</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection CreateServiceFromClass(this IServiceCollection serviceCollection,
|
||||
Type serviceClassType, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(serviceClassType, serviceClassType, lifetime));
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple classes as services to the DI container.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The extended IServiceCollection</param>
|
||||
/// <param name="serviceClassTypes">A list of class types</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection CreateServiceFromClasses(this IServiceCollection serviceCollection,
|
||||
IEnumerable<Type> serviceClassTypes, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
foreach(var serviceClassType in serviceClassTypes)
|
||||
{
|
||||
serviceCollection.TryAdd(new ServiceDescriptor(serviceClassType, serviceClassType, lifetime));
|
||||
}
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services based on a type that implements an interface, without adding the interface itself.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The extended interface</typeparam>
|
||||
/// <param name="serviceDescriptors">The extended IServiceCollection</param>
|
||||
/// <param name="lifetime">The lifetime of the services</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddServicesWithType<TType>(this IServiceCollection serviceDescriptors,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
var assembly = typeof(TType).Assembly;
|
||||
var types = assembly.DefinedTypes
|
||||
.Where(x => typeof(TType).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
|
||||
.ToArray();
|
||||
|
||||
if(types.Length == 0) return serviceDescriptors;
|
||||
|
||||
foreach(var type in types)
|
||||
{
|
||||
serviceDescriptors.TryAdd(new ServiceDescriptor(type.AsType(), type.AsType(), lifetime));
|
||||
}
|
||||
|
||||
return serviceDescriptors;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.Boot
|
||||
{
|
||||
public class GetServicesHandler(IServer server, ILogger<GetServicesHandler> logger, XDocument body) : Handler
|
||||
{
|
||||
private readonly IServer _server = server;
|
||||
private readonly ILogger<GetServicesHandler> _logger = logger;
|
||||
private readonly XDocument _body = body;
|
||||
private const string CommonUrl = "http://127.0.0.1:5120/eamuse";
|
||||
private string listeningAddress = "http://127.0.0.1:5120";
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("services");
|
||||
Method("get");
|
||||
}
|
||||
|
||||
public override Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var services = CreateCoreServicesElement();
|
||||
var document = new XDocument(new XElement("response", services));
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
private static XElement CreateCoreServicesElement()
|
||||
{
|
||||
var services = new XElement("services",
|
||||
new XAttribute("expire", "3600"),
|
||||
new XAttribute("method", "get"),
|
||||
new XAttribute("mode", "operation"),
|
||||
new XAttribute("status", "0"));
|
||||
|
||||
var coreServices = new string[]{
|
||||
"cardmng", "facility", "message", "numbering", "package", "pcbevent", "pcbtracker", "pkglist",
|
||||
"posevent", "userdata", "userid", "eacoin", "dlstatus", "netlog", "info", "reference", "sidmgr",
|
||||
"local", "local2", "lobby", "slocal", "slocal2", "sglocal", "sglocal2", "lab", "globby",
|
||||
"slobby", "sglobby", "eacharge"
|
||||
};
|
||||
|
||||
foreach(var service in coreServices)
|
||||
{
|
||||
services.Add(new XElement("item",
|
||||
new XAttribute("name", service),
|
||||
new XAttribute("url", $"{CommonUrl}/{service}")));
|
||||
}
|
||||
|
||||
services.Add(new XElement("item", new XAttribute("name", "ntp"),
|
||||
new XAttribute("url", "ntp://pool.ntp.org/")));
|
||||
|
||||
services.Add(new XElement("item", new XAttribute("name", "keepalive"),
|
||||
new XAttribute("url",
|
||||
"http://127.0.0.1:8083/keepalive?pa=127.0.0.1&ia=127.0.0.1&ga=127.0.0.1&ma=127.0.0.1&t1=2&t2=10")));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void AddKfcServices(XElement services)
|
||||
{
|
||||
const string sdvxurl = $"{CommonUrl}";
|
||||
string[] kfcServices = [
|
||||
"local", "local2", "lobby", "slocal", "slocal2", "sglocal", "sglocal2", "lab", "globby",
|
||||
"slobby", "sglobby"
|
||||
];
|
||||
|
||||
foreach(string service in kfcServices)
|
||||
services.Add(new XElement("item", new XAttribute("name", service), new XAttribute("url", sdvxurl)));
|
||||
}
|
||||
|
||||
private static void AddMdxServices(XElement services)
|
||||
{
|
||||
const string mdxurl = $"{CommonUrl}";
|
||||
string[] mdxServices = [
|
||||
"local", "local2", "lobby", "slocal", "slocal2", "sglocal", "sglocal2", "lab", "globby",
|
||||
"slobby", "sglobby"
|
||||
];
|
||||
|
||||
foreach(string service in mdxServices)
|
||||
services.Add(new XElement("item", new XAttribute("name", service), new XAttribute("url", mdxurl)));
|
||||
}
|
||||
|
||||
private static void AddM39Services(XElement services)
|
||||
{
|
||||
const string m39url = $"{CommonUrl}";
|
||||
string[] m39Services = [
|
||||
"local", "local2", "lobby", "slocal", "slocal2", "sglocal", "sglocal2", "lab", "globby",
|
||||
"slobby", "sglobby"
|
||||
];
|
||||
|
||||
foreach(string service in m39Services)
|
||||
services.Add(new XElement("item", new XAttribute("name", service), new XAttribute("url", m39url)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Server.Handlers.Boot;
|
||||
using Server.Attributes;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.Common
|
||||
{
|
||||
[Handler("pcbtracker", "alive")]
|
||||
public class AlivePcbTrackerHandler(ILogger<GetServicesHandler> logger, XDocument body) : IHandler
|
||||
{
|
||||
private readonly ILogger<GetServicesHandler> _logger = logger;
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var pcbTracker = new XElement("response",
|
||||
new XElement("pcbtracker",
|
||||
new XAttribute("status", "0"),
|
||||
new XAttribute("expire", "1200"),
|
||||
new XAttribute("ecenable", "1"),
|
||||
new XAttribute("eclimit", "0"),
|
||||
new XAttribute("limit", "0"),
|
||||
new XAttribute("time", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())));
|
||||
|
||||
var document = new XDocument(new XElement("response", pcbTracker));
|
||||
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.Common.Card
|
||||
{
|
||||
public class AuthPassCardManagmentHandker(ICardService cardService, XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ICardService _cardService = cardService;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("cardmng");
|
||||
Method("authpass");
|
||||
}
|
||||
|
||||
public override async Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var rootCall = _body.Root;
|
||||
var cardManagement = rootCall?.Element("cardmng")!;
|
||||
var referanceId = cardManagement.Attribute("refid")?.Value!;
|
||||
var password = cardManagement.Attribute("pass")?.Value!;
|
||||
|
||||
var card = await _cardService.FindByKonamiId(referanceId);
|
||||
|
||||
if(card == null)
|
||||
{
|
||||
var noCard = new XElement("cardmng", new XAttribute("status", "116"));
|
||||
return new XDocument(new XElement("response", noCard));
|
||||
}
|
||||
|
||||
if(card.User.Pin != int.Parse(password))
|
||||
{
|
||||
var wrongPassword = new XElement("cardmng", new XAttribute("status", "116"));
|
||||
return new XDocument(new XElement("response", wrongPassword));
|
||||
}
|
||||
|
||||
var authPass = new XElement("cardmng", new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(new XElement("response", authPass));
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.Common.Card
|
||||
{
|
||||
public class BindModelCardManagmentHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("cardmng");
|
||||
Method("bindmodel");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("cardmng")!;
|
||||
var cardmng = new XElement("cardmng", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", cardmng));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Server.Entities;
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.Common.Card
|
||||
{
|
||||
public class GetRefIdCardManagmentHandler(ICardService cardService, UserManager<User> userManager, XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ICardService _cardService = cardService;
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("cardmng");
|
||||
Method("getrefid");
|
||||
}
|
||||
|
||||
public override async Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var rootCall = _body.Root;
|
||||
var cardManagement = rootCall?.Element("cardmng")!;
|
||||
var cardId = cardManagement.Attribute("cardid")?.Value!;
|
||||
var password = cardManagement.Attribute("passwd")?.Value!;
|
||||
|
||||
var konamiId = _cardService.ConvertUidToKonamiId(cardId);
|
||||
|
||||
var card = new Entities.Card { RawId = cardId, KonamiId = konamiId };
|
||||
var user = new User { Pin = int.Parse(password), UserName = konamiId, Cards = [card] };
|
||||
|
||||
user.Cards.Add(card);
|
||||
|
||||
await _userManager.CreateAsync(user);
|
||||
|
||||
var getRefId = new XElement("cardmng", new XAttribute("status", "0"), new XAttribute("refid", konamiId), new XAttribute("dataid", konamiId));
|
||||
|
||||
var document = new XDocument(new XElement("response", getRefId));
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.Common.Card
|
||||
{
|
||||
public class InquireCardManagmentHandlerInquireCardManagmentHandler(ICardService cardService, XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ICardService _cardService = cardService;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("cardmng");
|
||||
Method("inquire");
|
||||
}
|
||||
|
||||
public override async Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var cardId = _body.Root?.Element("cardmng")?.Attribute("cardid")?.Value;
|
||||
|
||||
if(string.IsNullOrEmpty(cardId))
|
||||
{
|
||||
var noCardId = new XElement("cardmng", new XAttribute("status", "111"));
|
||||
return new XDocument(new XElement("response", noCardId));
|
||||
}
|
||||
|
||||
var konamiId = _cardService.ConvertUidToKonamiId(cardId);
|
||||
if(string.IsNullOrEmpty(konamiId))
|
||||
{
|
||||
var noKonamiId = new XElement("cardmng", new XAttribute("status", "111"));
|
||||
return new XDocument(new XElement("response", noKonamiId));
|
||||
}
|
||||
|
||||
var exisitngCard = await _cardService.FindByKonamiId(konamiId);
|
||||
|
||||
if(exisitngCard == null)
|
||||
{
|
||||
var noCard = new XElement("cardmng", new XAttribute("status", "112"));
|
||||
return new XDocument(new XElement("response", noCard));
|
||||
}
|
||||
|
||||
var cardManagment = new XElement("cardmng", new XAttribute("binded", "0"), new XAttribute("dataid", konamiId),
|
||||
new XAttribute("ecflag", "1"), new XAttribute("expired", "0"), new XAttribute("newflag", "1"), new XAttribute("extidflag", "1"),
|
||||
new XAttribute("refid", konamiId), new XAttribute("status", "0"), new XAttribute("useridflag", "1"));
|
||||
|
||||
var document = new XDocument(new XElement("response", cardManagment));
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
using Server.Attributes;
|
||||
|
||||
namespace Server.Handlers.Common
|
||||
{
|
||||
[Handler("facility", "get")]
|
||||
public class GetFacilityHandler(IServer server, XDocument body) : IHandler
|
||||
{
|
||||
private readonly IServer _server = server;
|
||||
private IServerAddressesFeature? serverAddressesFeature => _server.Features.Get<IServerAddressesFeature>();
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var port = "8083";
|
||||
|
||||
var facility = new XElement("facility",
|
||||
new XAttribute("status", "0"));
|
||||
|
||||
var location = new XElement("location",
|
||||
new XElement("id", "00000000"),
|
||||
new XElement("country", "US"),
|
||||
new XElement("region", "NA"),
|
||||
new XElement("name", "Medusa"),
|
||||
new XElement("type", 0, new XAttribute("__type", "u8")));
|
||||
|
||||
var line = new XElement("line",
|
||||
new XElement("id", "00000000"),
|
||||
new XElement("class", 0, new XAttribute("__type", "u8")));
|
||||
|
||||
var portfw = new XElement("portfw",
|
||||
new XElement("globalip", "127.0.0.1", new XAttribute("__type", "ip4")),
|
||||
new XElement("globalport", "5246", new XAttribute("__type", "u16")),
|
||||
new XElement("privateport", "5246", new XAttribute("__type", "u16")));
|
||||
|
||||
var _public = new XElement("public",
|
||||
new XElement("flag", 1, new XAttribute("__type", "u8")),
|
||||
new XElement("name", "Medusa"),
|
||||
new XElement("latitude", "0.0"),
|
||||
new XElement("longitude", "0.0"));
|
||||
|
||||
var share = new XElement("share",
|
||||
new XElement("eacoin",
|
||||
new XElement("notchamount", 3000, new XAttribute("__type", "s32")),
|
||||
new XElement("notchcount", 3, new XAttribute("__type", "s32")),
|
||||
new XElement("supplylimit", 100000, new XAttribute("__type", "s32"))),
|
||||
new XElement("url",
|
||||
new XElement("eapass", "http://eagate.573.jp"),
|
||||
new XElement("arcadefan", "http://eagate.573.jp"),
|
||||
new XElement("konaminetdx", "http://eagate.573.jp"),
|
||||
new XElement("konamiid", "http://eagate.573.jp"),
|
||||
new XElement("eagate", "http://eagate.573.jp")));
|
||||
|
||||
facility.Add(location, line, portfw, _public, share);
|
||||
|
||||
var document = new XDocument(new XElement("response", facility));
|
||||
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
using Server.Attributes;
|
||||
|
||||
namespace Server.Handlers.Common
|
||||
{
|
||||
[Handler("message", "get")]
|
||||
public class GetMessageHandler(XDocument body) : IHandler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var message = new XElement("message",
|
||||
new XAttribute("expire", "300"),
|
||||
new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response", message));
|
||||
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
using Server.Attributes;
|
||||
|
||||
namespace Server.Handlers.Common.OTAUpdates
|
||||
{
|
||||
[Handler("package", "list")]
|
||||
public class ListPackageHandler(XDocument body) : IHandler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var package = new XElement("package", new XAttribute("expire", "600"), new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(new XElement("response", package));
|
||||
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
using Server.Attributes;
|
||||
|
||||
namespace Server.Handlers.Common.OTAUpdates
|
||||
{
|
||||
[Handler("dlstatus", "progress")]
|
||||
public class ProgressDLStatusHandler(XDocument body) : IHandler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var dlStatus = new XElement("dlstatus", new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(new XElement("response", dlStatus));
|
||||
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
using Server.Attributes;
|
||||
|
||||
namespace Server.Handlers.Common
|
||||
{
|
||||
[Handler("pcbevent", "put")]
|
||||
public class PutPcbEventHandler(ILogger<PutPcbEventHandler> logger, XDocument body) : IHandler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ILogger<PutPcbEventHandler> _logger = logger;
|
||||
|
||||
public Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var rootCallElement = _body.Root;
|
||||
|
||||
var itemElement = rootCallElement?.Element("pcbevent")?.Element("item");
|
||||
|
||||
var timeElement = itemElement?.Element("time");
|
||||
string time = timeElement is not null ? UnixTimeStampToDateTime(double.Parse(timeElement.Value)).ToString() : "";
|
||||
|
||||
_logger.LogInformation("PCBEvent: tag={Tag} srcid={SrcId} model={Model} name={Name} time={Time}",
|
||||
rootCallElement?.Attribute("tag")?.Value ?? "",
|
||||
rootCallElement?.Attribute("srcid")?.Value ?? "",
|
||||
rootCallElement?.Attribute("model")?.Value ?? "",
|
||||
itemElement?.Element("name")?.Value ?? "",
|
||||
time
|
||||
);
|
||||
|
||||
var pcbEvent = new XElement("response",
|
||||
new XElement("pcbevent",
|
||||
new XAttribute("status", "0")));
|
||||
|
||||
var document = new XDocument(new XElement("response", pcbEvent));
|
||||
return Task.FromResult(document);
|
||||
}
|
||||
|
||||
public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
|
||||
{
|
||||
// Unix timestamp is seconds past epoch
|
||||
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
dateTime = dateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||
return dateTime;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Server.Entities;
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.LA9
|
||||
{
|
||||
public class ChargeEaChargeHandler(ICardService cardService, ISessionService sessionService, UserManager<User> userManager, XDocument body): Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ICardService _cardService = cardService;
|
||||
private readonly ISessionService _sessionService = sessionService;
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("eacharge");
|
||||
Method("charge");
|
||||
}
|
||||
public override async Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var rootCall = _body.Root;
|
||||
var charge = rootCall?.Element("eacharge")!;
|
||||
var amount = int.Parse(charge.Element("chargenum")?.Value!) * 1000;
|
||||
var session = charge.Element("sessid")?.Value!;
|
||||
|
||||
var foundSession = _sessionService.GetSession(session);
|
||||
|
||||
var card = await _cardService.FindByCardId(foundSession.refId)!;
|
||||
card.User.PaseliAmount += amount;
|
||||
|
||||
await _userManager.UpdateAsync(card.User);
|
||||
|
||||
var balance = new XElement("balance", card.User.PaseliAmount, new XAttribute("__type", "s32"));
|
||||
var chargeDailyLimit = new XElement("chargedailylimit", 100000, new XAttribute("__type", "s32"));
|
||||
var chargeDaily = new XElement("chargedaily", 0, new XAttribute("__type", "s32"));
|
||||
var chargepoint = new XElement("chargepoint", amount, new XAttribute("__type", "s32"));
|
||||
|
||||
var eaCharge = new XElement("charge", balance, chargeDailyLimit, chargeDaily, chargepoint, new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", eaCharge));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.LA9
|
||||
{
|
||||
public class CheckInEaChargeHandler(ISessionService sessionService, ICardService cardService, XDocument body): Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
private readonly ISessionService _sessionService = sessionService;
|
||||
private readonly ICardService _cardService = cardService;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("eacharge");
|
||||
Method("checkin");
|
||||
}
|
||||
public override async Task<XDocument> HandleAsync(string model)
|
||||
{
|
||||
var rootCall = _body.Root;
|
||||
var eaCharge = rootCall?.Element("eacharge")!;
|
||||
var cardId = eaCharge.Element("cardid")?.Value!;
|
||||
|
||||
var sessionId = _sessionService.AddSession(cardId);
|
||||
|
||||
var card = await _cardService.FindByCardId(cardId);
|
||||
|
||||
var userPaseli = card!.User.PaseliAmount;
|
||||
|
||||
var sessseq = new XElement("sessseq", 0, new XAttribute("__type", "s32"));
|
||||
var acname = new XElement("acname", "DUMMY_NAME", new XAttribute("__type", "str"));
|
||||
var balance = new XElement("balance", userPaseli, new XAttribute("__type", "s32"));
|
||||
var buyablep = new XElement("buyablep", 100000, new XAttribute("__type", "s32"));
|
||||
var sessionIdXElement = new XElement("sessid", sessionId, new XAttribute("__type", "str"));
|
||||
var eacharge = new XElement("eacharge", sessseq, acname, balance, buyablep, sessionIdXElement, new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", eacharge));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Server.Services;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.LA9
|
||||
{
|
||||
public class CheckoutEaCharge(ISessionService sessionService, XDocument body): Handler
|
||||
{
|
||||
private readonly ISessionService _sessionService = sessionService;
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("eacharge");
|
||||
Method("checkout");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var eaCharge = _body.Root?.Element("eacharge")!;
|
||||
var sessionId = eaCharge.Element("sessid")!.Value!;
|
||||
|
||||
_sessionService.removeSession(sessionId);
|
||||
|
||||
var checkoutCharge = new XElement("eacharge", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", checkoutCharge));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.LA9
|
||||
{
|
||||
public class GetConfigEaChargeHandler(XDocument body): Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("eacharge");
|
||||
Method("getconf");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var articlerevision = new XElement("articlerevision", 1, new XAttribute("__type", "str"));
|
||||
|
||||
var articletype1 = new XElement("articletype", "DOCMT_0000", new XAttribute("__type", "str"));
|
||||
var articledoc1 = new XElement("articledoc", new XAttribute("__type", "str"));
|
||||
var item1 = new XElement("item", articletype1, articledoc1);
|
||||
|
||||
var articletype2 = new XElement("articletype", "DOCMT_0001", new XAttribute("__type", "str"));
|
||||
var articledoc2 = new XElement("articledoc", new XAttribute("__type", "str"));
|
||||
var item2 = new XElement("item", articletype2, articledoc2);
|
||||
|
||||
var articletype3 = new XElement("articletype", "DOCMT_0002", new XAttribute("__type", "str"));
|
||||
var articledoc3 = new XElement("articledoc", new XAttribute("__type", "str"));
|
||||
var item3 = new XElement("item", articletype3, articledoc3);
|
||||
|
||||
var articletype4 = new XElement("articletype", "DOCMT_0003", new XAttribute("__type", "str"));
|
||||
var articledoc4 = new XElement("articledoc", new XAttribute("__type", "str"));
|
||||
var item4 = new XElement("item", articletype4, articledoc4);
|
||||
|
||||
var articletype5 = new XElement("articletype", "URL_0001_A", new XAttribute("__type", "str"));
|
||||
var articledoc5 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item5 = new XElement("item", articletype5, articledoc5);
|
||||
|
||||
var articletype6 = new XElement("articletype", "URL_0001_B", new XAttribute("__type", "str"));
|
||||
var articledoc6 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item6 = new XElement("item", articletype6, articledoc6);
|
||||
|
||||
var articletype7 = new XElement("articletype", "URL_0002_A", new XAttribute("__type", "str"));
|
||||
var articledoc7 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item7 = new XElement("item", articletype7, articledoc7);
|
||||
|
||||
var articletype8 = new XElement("articletype", "URL_0002_B", new XAttribute("__type", "str"));
|
||||
var articledoc8 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item8 = new XElement("item", articletype8, articledoc8);
|
||||
|
||||
var articletype9 = new XElement("articletype", "URL_0003_A", new XAttribute("__type", "str"));
|
||||
var articledoc9 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item9 = new XElement("item", articletype9, articledoc9);
|
||||
|
||||
var articletype10 = new XElement("articletype", "URL_0003_B", new XAttribute("__type", "str"));
|
||||
var articledoc10 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item10 = new XElement("item", articletype10, articledoc10);
|
||||
|
||||
var articletype11 = new XElement("articletype", "URL_0004_A", new XAttribute("__type", "str"));
|
||||
var articledoc11 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item11 = new XElement("item", articletype11, articledoc11);
|
||||
|
||||
var articletype12 = new XElement("articletype", "URL_0004_B", new XAttribute("__type", "str"));
|
||||
var articledoc12 = new XElement("articledoc", "http://eagate.573.jp", new XAttribute("__type", "str"));
|
||||
var item12 = new XElement("item", articletype12, articledoc12);
|
||||
|
||||
var articletype13 = new XElement("articletype", "PASELIUNIT", new XAttribute("__type", "str"));
|
||||
var articledoc13 = new XElement("articledoc", "P", new XAttribute("__type", "str"));
|
||||
var item13 = new XElement("item", articletype13, articledoc13);
|
||||
|
||||
var articlelist = new XElement("articlelist", item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13);
|
||||
var chargearticle = new XElement("chargearticle", articlerevision, articlelist);
|
||||
|
||||
var chargedaily = new XElement("chargedaily", 0, new XAttribute("__type", "s32"));
|
||||
var chargedailylimit = new XElement("chargedailylimit", 100000, new XAttribute("__type", "s32"));
|
||||
var chargedetail = new XElement("chargedetail", chargedaily, chargedailylimit);
|
||||
|
||||
var currentcode = new XElement("currentcode", 0, new XAttribute("__type", "s32"));
|
||||
var lastchargestatus = new XElement("lastchargestatus", 1, new XAttribute("__type", "s32"));
|
||||
var chargestatus = new XElement("chargestatus", currentcode, lastchargestatus);
|
||||
|
||||
var eacharge = new XElement("eacharge",
|
||||
new XAttribute("status", "0"), new XAttribute("expire", "1200"), chargearticle, chargedetail, chargestatus);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
eacharge
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.M39
|
||||
{
|
||||
public class BootPCB24Handler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("pcb24");
|
||||
Method("boot");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var pcb24 = new XElement("pcb24",
|
||||
new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
pcb24
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class CommonGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("common");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var newGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", newGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class LogGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("log");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var newGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", newGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class MessageGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("message");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var newGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", newGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class NewGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("new");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var newGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", newGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class RecorderGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("recorder");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var recorderGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", recorderGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class ShopGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("shop");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var newGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", newGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Handlers.MDX._2014032700
|
||||
{
|
||||
public class TaxInfoGameHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("game");
|
||||
Method("tax_info");
|
||||
GameCode("MDX");
|
||||
MinVer("2014032700");
|
||||
MaxVer("2014032700");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var game = _body.Root?.Element("game")!;
|
||||
var recorderGame = new XElement("game", new XAttribute("status", "0"));
|
||||
var document = new XDocument(new XElement("response", recorderGame));
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers
|
||||
{
|
||||
public class SubscribeAsGuestUserIdHandler(XDocument body): Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("userid");
|
||||
Method("subscribeAsGuest");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var subscribeAsGuest = new XElement("userid", new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(new XElement("response", subscribeAsGuest));
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.TBS
|
||||
{
|
||||
public class GetGachaSettingDataTBSHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("tbs");
|
||||
Method("getgachasettingdata");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var tbs = new XElement("tbs",
|
||||
new XAttribute("status", "0")
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
tbs
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.TBS
|
||||
{
|
||||
public class GetServerMessageDataTBSHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("tbs");
|
||||
Method("getservermessagedata");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var tbs = new XElement("tbs",
|
||||
new XAttribute("status", "0")
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
tbs
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.TBS
|
||||
{
|
||||
public class ResetMatchDataTBSHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("tbs");
|
||||
Method("resetmatchdata");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var tbs = new XElement("tbs",
|
||||
new XAttribute("status", "0")
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
tbs
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.TBS
|
||||
{
|
||||
public class SetClientLogDataTBSHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("tbs");
|
||||
Method("setclientlogdata");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var tbs = new XElement("tbs",
|
||||
new XAttribute("status", "0"));
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
tbs
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.TBS
|
||||
{
|
||||
public class SetEventLogDataTBSHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("tbs");
|
||||
Method("seteventlogdata");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var tbs = new XElement("tbs",
|
||||
new XAttribute("status", "0")
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
tbs
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.VFG
|
||||
{
|
||||
public class PutMsgVfglogHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("vfglog");
|
||||
Method("put_msg");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
var vfglog = new XElement("vfglog",
|
||||
new XAttribute("status", "0")
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
vfglog
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Handlers.VFG
|
||||
{
|
||||
public class ServiceListVfgacHandler(XDocument body) : Handler
|
||||
{
|
||||
private readonly XDocument _body = body;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Module("vfgac");
|
||||
Method("service_list");
|
||||
}
|
||||
|
||||
public override XDocument Handle(string model)
|
||||
{
|
||||
|
||||
var serviceUrl = new XElement("service_url", "http://127.0.0.1:5120/eamuse");
|
||||
var service1 = new XElement("service", new XAttribute("service", "http://127.0.0.1:5120/eamuse"), new XAttribute("mode", "test"), "http://127.0.0.1:5120/eamuse");
|
||||
var services = new XElement("services", service1);
|
||||
|
||||
var vfgac = new XElement("vfgac",
|
||||
new XAttribute("status", "0"),
|
||||
serviceUrl,
|
||||
services
|
||||
);
|
||||
|
||||
var document = new XDocument(
|
||||
new XElement("response",
|
||||
vfgac
|
||||
)
|
||||
);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,81 @@
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Xml.Linq;
|
||||
using Server.Utils;
|
||||
using KbinXml.Net;
|
||||
|
||||
namespace Server.Middlewares;
|
||||
|
||||
public class BodyParsingMiddleware(RequestDelegate next)
|
||||
{
|
||||
static readonly byte[] Key =
|
||||
Convert.FromHexString("00000000000069D74627D985EE2187161570D08D93B12455035B6DF0D8205DF5");
|
||||
|
||||
private readonly RequestDelegate _next = next;
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
if(context.Request.Method == "GET" || !context.Request.Path.ToString().Contains("eamuse", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var body = await ParseRequest(context);
|
||||
|
||||
context.Items["Encoding"] = body.Declaration?.Encoding;
|
||||
var bodyString = body.ToString();
|
||||
if(string.IsNullOrEmpty(bodyString))
|
||||
{
|
||||
context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(""));
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
context.Request.Body = new MemoryStream(Encoding.GetEncoding(932).GetBytes(bodyString));
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
|
||||
public async Task<XDocument> ParseRequest(HttpContext context)
|
||||
{
|
||||
var isCompressed = context.Request.Headers["X-Compress"].ToString().Contains("lz77");
|
||||
var info = context.Request.Headers["X-Eamuse-Info"].FirstOrDefault();
|
||||
var contentLength = context.Request.Headers.ContentLength ?? 0;
|
||||
byte[] data = new byte[(int)contentLength];
|
||||
|
||||
await context.Request.Body.ReadAsync(data.AsMemory(0, (int)contentLength));
|
||||
|
||||
if(info is not null)
|
||||
{
|
||||
string[] infoParts = info.Split('-');
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
Key[i] = Convert.ToByte((infoParts[1] + infoParts[2]).Substring(i << 1, 2), 0x10);
|
||||
}
|
||||
|
||||
byte[] rc4Key = MD5.HashData(Key);
|
||||
data = RC4.Decrypt(rc4Key, data);
|
||||
}
|
||||
|
||||
if(isCompressed)
|
||||
{
|
||||
data = LZ77.Decompress(data);
|
||||
}
|
||||
|
||||
var returnData = new XDocument();
|
||||
|
||||
try
|
||||
{
|
||||
returnData = KbinConverter.ReadXmlLinq(data);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
//Data is now xml in konami binary form
|
||||
return returnData;
|
||||
}
|
||||
|
||||
}
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Server;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20241208214019_Init")]
|
||||
partial class Init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.Card", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("KonamiId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RawId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Cards");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PaseliAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Pin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<int>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<int>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.Card", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", "User")
|
||||
.WithMany("Cards")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("Cards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Init : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
PaseliAmount = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Pin = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
UserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "TEXT", nullable: true),
|
||||
SecurityStamp = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "TEXT", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
RoleId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ProviderKey = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
UserId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
RoleId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Cards",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
KonamiId = table.Column<string>(type: "TEXT", nullable: false),
|
||||
RawId = table.Column<string>(type: "TEXT", nullable: false),
|
||||
UserId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Cards", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Cards_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Cards_UserId",
|
||||
table: "Cards",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Cards");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Server;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
partial class AppDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.Card", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("KonamiId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RawId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Cards", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PaseliAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Pin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<int>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<int>", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.Card", b =>
|
||||
{
|
||||
b.HasOne("Server.Entities.User", "User")
|
||||
.WithMany("Cards")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Server.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("Cards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using KbinXml.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Server;
|
||||
using Server.Entities;
|
||||
using Server.Extensions;
|
||||
using Server.Middlewares;
|
||||
using Server.Request;
|
||||
using Server.Services;
|
||||
using Server.Utils;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
var key =
|
||||
Convert.FromHexString("00000000000069D74627D985EE2187161570D08D93B12455035B6DF0D8205DF5");
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddHandlers();
|
||||
|
||||
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlite("Data Source=Medusa.db;"));
|
||||
|
||||
builder.Services.AddIdentityCore<User>(config =>
|
||||
{
|
||||
config.Password.RequiredLength = 8;
|
||||
config.SignIn.RequireConfirmedEmail = true;
|
||||
config.Lockout.AllowedForNewUsers = true;
|
||||
}).AddEntityFrameworkStores<AppDbContext>();
|
||||
|
||||
builder.Services.AddTransient<ICardService, CardService>();
|
||||
builder.Services.AddSingleton<ISessionService, SessionService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
//app.UseHttpsRedirection();
|
||||
app.UseMiddleware<BodyParsingMiddleware>();
|
||||
app.UseHandlers();
|
||||
|
||||
var eamuseGroup = app.MapGroup("eamuse");
|
||||
|
||||
eamuseGroup.MapPost("/{model}/{module}/{method}", (string model, string module, string method,
|
||||
[FromServices] IHttpContextAccessor httpContextAccessor) =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
eamuseGroup.MapPost("/{m}", async (string m, [FromQuery] string model, [FromQuery] string? module, [FromQuery] string? method, [FromQuery] string? f,
|
||||
HttpContext httpContext, [FromServices] ILogger<Program> logger, [FromServices] IHandlerService handlerService) =>
|
||||
{
|
||||
// Enable buffering to allow multiple reads of the request body
|
||||
httpContext.Request.EnableBuffering();
|
||||
|
||||
// The body is 932 encoded xml
|
||||
using var reader = new StreamReader(httpContext.Request.Body, Encoding.GetEncoding(932), false, 1024, true);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
|
||||
httpContext.Request.Body.Position = 0;
|
||||
|
||||
bool compress = httpContext.Request.Headers["X-Compress"].ToString().Contains("lz77");
|
||||
bool encrypt = httpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault() is not null;
|
||||
|
||||
var amusementRequest = new AmusementRequest() { Model = model, Module = module ?? "", Method = method ?? "" };
|
||||
|
||||
if(!string.IsNullOrEmpty(f))
|
||||
{
|
||||
var fParts = f.Split('.');
|
||||
amusementRequest.Module = fParts[0];
|
||||
amusementRequest.Method = fParts[1];
|
||||
}
|
||||
|
||||
logger.LogInformation("Handling {Module} {Method}", amusementRequest.Module, amusementRequest.Method);
|
||||
|
||||
var document = new XDocument();
|
||||
|
||||
if (!string.IsNullOrEmpty(body))
|
||||
document = XDocument.Parse(body);
|
||||
|
||||
var responseXml = await handlerService.Handle(amusementRequest.Model, amusementRequest.Module, amusementRequest.Method, document);
|
||||
|
||||
var encoding = httpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS";
|
||||
|
||||
switch(encoding)
|
||||
{
|
||||
case "shift_jis":
|
||||
encoding = "ShiftJIS";
|
||||
break;
|
||||
case "us-ascii":
|
||||
encoding = "ASCII";
|
||||
break;
|
||||
case "utf-8":
|
||||
encoding = "UTF8";
|
||||
break;
|
||||
case "euc-jp":
|
||||
encoding = "EUC_JP";
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] encodedBody = KbinConverter.Write(responseXml, (KnownEncodings)Enum.Parse(typeof(KnownEncodings), encoding, true));
|
||||
|
||||
if(compress)
|
||||
{
|
||||
encodedBody = LZ77.CompressEmpty(encodedBody);
|
||||
}
|
||||
|
||||
if(encrypt)
|
||||
{
|
||||
string[] originalInfo = httpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault()?.Split('-') ?? [];
|
||||
byte[] part = Convert.FromHexString((originalInfo[1] + originalInfo[2]));
|
||||
for(int i = 0; i < 6; i++)
|
||||
key[i] = part[i];
|
||||
var rc4Key = MD5.HashData(key);
|
||||
encodedBody = RC4.Encrypt(rc4Key, encodedBody);
|
||||
|
||||
httpContext.Response.Headers.Append("X-Eamuse-Info", string.Join('-', originalInfo));
|
||||
}
|
||||
|
||||
return TypedResults.Bytes(encodedBody, "application/octet-stream");
|
||||
});
|
||||
|
||||
eamuseGroup.MapPost("/", async ([FromQuery] string model, [FromQuery] string? module, [FromQuery] string? method, [FromQuery] string? f,
|
||||
HttpContext httpContext, [FromServices] ILogger<Program> logger, [FromServices] IHandlerService handlerService) =>
|
||||
{
|
||||
// Enable buffering to allow multiple reads of the request body
|
||||
httpContext.Request.EnableBuffering();
|
||||
var body = "";
|
||||
// The body is 932 encoded xml
|
||||
if(httpContext.Request.Body.Length != 0)
|
||||
{
|
||||
using var reader = new StreamReader(httpContext.Request.Body, Encoding.GetEncoding(932), false, 1024, true);
|
||||
body = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
httpContext.Request.Body.Position = 0;
|
||||
|
||||
bool compress = httpContext.Request.Headers["X-Compress"].ToString().Contains("lz77");
|
||||
bool encrypt = httpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault() is not null;
|
||||
|
||||
var amusementRequest = new AmusementRequest() { Model = model, Module = module ?? "", Method = method ?? ""};
|
||||
|
||||
if (!string.IsNullOrEmpty(f))
|
||||
{
|
||||
var fParts = f.Split('.');
|
||||
amusementRequest.Module = fParts[0];
|
||||
amusementRequest.Method = fParts[1];
|
||||
}
|
||||
|
||||
logger.LogInformation("Handling {Module} {Method}", amusementRequest.Module, amusementRequest.Method);
|
||||
|
||||
var document = new XDocument();
|
||||
|
||||
if(!string.IsNullOrEmpty(body))
|
||||
document = XDocument.Parse(body);
|
||||
|
||||
var responseXml = await handlerService.Handle(amusementRequest.Model, amusementRequest.Module, amusementRequest.Method, document);
|
||||
|
||||
var encoding = httpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS";
|
||||
|
||||
switch(encoding)
|
||||
{
|
||||
case "shift_jis":
|
||||
encoding = "ShiftJIS";
|
||||
break;
|
||||
case "us-ascii":
|
||||
encoding = "ASCII";
|
||||
break;
|
||||
case "utf-8":
|
||||
encoding = "UTF8";
|
||||
break;
|
||||
case "euc-jp":
|
||||
encoding = "EUC_JP";
|
||||
break;
|
||||
}
|
||||
|
||||
var encodedBody = KbinConverter.Write(responseXml, (KnownEncodings)Enum.Parse(typeof(KnownEncodings), encoding, true));
|
||||
|
||||
if(compress)
|
||||
{
|
||||
encodedBody = LZ77.CompressEmpty(encodedBody);
|
||||
}
|
||||
|
||||
if (!encrypt) return TypedResults.Bytes(encodedBody, "application/octet-stream");
|
||||
var originalInfo = httpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault()?.Split('-') ?? [];
|
||||
var part = Convert.FromHexString((originalInfo[1] + originalInfo[2]));
|
||||
for(var i = 0; i < 6; i++)
|
||||
key[i] = part[i];
|
||||
var rc4Key = MD5.HashData(key);
|
||||
encodedBody = RC4.Encrypt(rc4Key, encodedBody);
|
||||
|
||||
httpContext.Response.Headers.Append("X-Eamuse-Info", string.Join('-', originalInfo));
|
||||
|
||||
return TypedResults.Bytes(encodedBody, "application/octet-stream");
|
||||
});
|
||||
|
||||
app.MapFallbackToFile("/index.html");
|
||||
|
||||
await using var scope = app.Services.CreateAsyncScope();
|
||||
|
||||
var appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await appDbContext.Database.MigrateAsync();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:52284",
|
||||
"sslPort": 44317
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"applicationUrl": "http://localhost:5120",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"applicationUrl": "https://localhost:7059;http://localhost:5120",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Server.Request
|
||||
{
|
||||
public class AmusementRequest
|
||||
{
|
||||
public required string Model { get; init; }
|
||||
public required string Module { get; set; }
|
||||
public required string Method { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<SpaRoot>..\Client</SpaRoot>
|
||||
<SpaProxyLaunchCommand>npm run dev</SpaProxyLaunchCommand>
|
||||
<SpaProxyServerUrl>https://localhost:5173</SpaProxyServerUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Abstractions\Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Client\Client.esproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="KbinXml.Net" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaProxy">
|
||||
<Version>9.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
@Server_HostAddress = http://localhost:5120
|
||||
|
||||
GET {{Server_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@@ -0,0 +1,208 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Server.Entities;
|
||||
using Server.Utils;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Services;
|
||||
|
||||
public class CardService : ICardService
|
||||
{
|
||||
private const string Alphabet = "0123456789ABCDEFGHJKLMNPRSTUWXYZ";
|
||||
private readonly byte[] RawKey = Encoding.ASCII.GetBytes("?I'llB2c.YouXXXeMeHaYpy!");
|
||||
private readonly DesEncryption _desEncryption;
|
||||
|
||||
private readonly ILogger<CardService> _logger;
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public CardService(ILogger<CardService> logger, AppDbContext context)
|
||||
{
|
||||
var encryptionKey = RawKey.Select(x => (byte)(x * 2)).ToArray();
|
||||
_desEncryption = new DesEncryption(encryptionKey);
|
||||
_logger = logger;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public string ConvertKonamiIdToUid(string konamiId)
|
||||
{
|
||||
if(konamiId.Length != 16)
|
||||
{
|
||||
_logger.LogError("Invalid Konami ID length must be 16 characters");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int cardType = konamiId[14] == '1' ? 1 : konamiId[14] == '2' ? 2 : -1;
|
||||
|
||||
if(cardType == -1)
|
||||
{
|
||||
_logger.LogError("Invalid Konami ID");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var card = konamiId.Select(k => (byte)Alphabet.IndexOf(k)).ToArray();
|
||||
|
||||
if(card[11] % 2 != card[12] % 2 || card[13] != (card[12] ^ 1) || card[15] != CalculateChecksum(card))
|
||||
{
|
||||
|
||||
_logger.LogError("Invalid card data");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
for(int i = 13; i > 0; i--)
|
||||
{
|
||||
card[i] ^= card[i - 1];
|
||||
}
|
||||
|
||||
card[0] ^= (byte)cardType;
|
||||
|
||||
var packed = Pack5(card.Take(13).ToArray()).Take(8).ToArray();
|
||||
var decrypted = _desEncryption.Decrypt(packed).Reverse().ToArray();
|
||||
|
||||
string cardId = BitConverter.ToString(decrypted).Replace("-", "").ToUpper();
|
||||
|
||||
if(cardType == 1 && !cardId.StartsWith("E004") || cardType == 2 && cardId[0] != '0')
|
||||
{
|
||||
_logger.LogError("Invalid card `type");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return cardId;
|
||||
}
|
||||
|
||||
public string ConvertUidToKonamiId(string uid)
|
||||
{
|
||||
if(uid.Length != 16)
|
||||
{
|
||||
_logger.LogError("Invalid UID length must be 16 characters");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int cardType = uid.StartsWith("E004") ? 1 : uid[0] == '0' ? 2 : -1;
|
||||
|
||||
if(cardType == -1)
|
||||
{
|
||||
_logger.LogError("Invalid UID prefix");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var konamiId = Enumerable.Range(0, uid.Length / 2)
|
||||
.Select(x => Convert.ToByte(uid.Substring(x * 2, 2), 16))
|
||||
.ToArray();
|
||||
|
||||
konamiId = konamiId.Reverse().ToArray();
|
||||
|
||||
if(konamiId.Length != 8)
|
||||
{
|
||||
_logger.LogError("Invalid UID length. Must be 8 bytes");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var encryptedId = _desEncryption.Encrypt(konamiId);
|
||||
|
||||
if(encryptedId.Length != 8)
|
||||
{
|
||||
_logger.LogError("Invalid ID length. Must be 8 bytes");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var unpackedId = Unpack5(encryptedId);
|
||||
unpackedId = unpackedId.Take(13).Concat(new byte[] { 0, 0, 0 }).ToArray();
|
||||
|
||||
if(unpackedId.Length != 16)
|
||||
{
|
||||
_logger.LogError("Invalid unpacked ID length. Must be 16 bytes");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
unpackedId[0] ^= (byte)cardType;
|
||||
unpackedId[13] = 1;
|
||||
|
||||
for(int i = 1; i < 14; i++)
|
||||
{
|
||||
unpackedId[i] ^= unpackedId[i - 1];
|
||||
}
|
||||
|
||||
unpackedId[14] = (byte)cardType;
|
||||
unpackedId[15] = (byte)CalculateChecksum(unpackedId);
|
||||
|
||||
return string.Concat(unpackedId.Select(u => Alphabet[u]));
|
||||
}
|
||||
|
||||
private static byte[] Unpack5(byte[] data)
|
||||
{
|
||||
// Convert each byte to an 8-bit binary string and concatenate them
|
||||
var binaryString = new StringBuilder();
|
||||
foreach(byte b in data)
|
||||
{
|
||||
binaryString.Append(Convert.ToString(b, 2).PadLeft(8, '0'));
|
||||
}
|
||||
|
||||
// Ensure the total length is a multiple of 5 by padding with zeroes if necessary
|
||||
int remainder = binaryString.Length % 5;
|
||||
if(remainder != 0)
|
||||
{
|
||||
binaryString.Append(new string('0', 5 - remainder));
|
||||
}
|
||||
|
||||
// Convert the 5-bit chunks back into bytes
|
||||
var result = new List<byte>();
|
||||
for(int i = 0; i < binaryString.Length; i += 5)
|
||||
{
|
||||
string chunk = binaryString.ToString(i, 5);
|
||||
result.Add(Convert.ToByte(chunk, 2));
|
||||
}
|
||||
|
||||
return [.. result];
|
||||
}
|
||||
|
||||
private static byte[] Pack5(byte[] data)
|
||||
{
|
||||
var packed = new StringBuilder();
|
||||
foreach(byte b in data)
|
||||
{
|
||||
packed.Append(Convert.ToString(b, 2).PadLeft(5, '0'));
|
||||
}
|
||||
|
||||
// Padding if not a multiple of 8
|
||||
if(packed.Length % 8 != 0)
|
||||
{
|
||||
packed.Append('0', 8 - packed.Length % 8);
|
||||
}
|
||||
|
||||
return Enumerable.Range(0, packed.Length / 8)
|
||||
.Select(i => Convert.ToByte(packed.ToString().Substring(i * 8, 8), 2))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static byte CalculateChecksum(byte[] data)
|
||||
{
|
||||
int checksum = 0;
|
||||
for(int i = 0; i < 15; i++)
|
||||
{
|
||||
if(i >= data.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
checksum += data[i] * ((i % 3) + 1);
|
||||
}
|
||||
|
||||
// Reduce the checksum to fit within 5 bits
|
||||
while(checksum > 31)
|
||||
{
|
||||
checksum = (checksum >> 5) + (checksum & 31);
|
||||
}
|
||||
|
||||
// Return the checksum as a byte
|
||||
return (byte)checksum;
|
||||
|
||||
}
|
||||
|
||||
public Task<Card?> FindByKonamiId(string konamiId)
|
||||
{
|
||||
return _context.Cards.Include(x => x.User).FirstOrDefaultAsync(c => c.KonamiId == konamiId);
|
||||
}
|
||||
|
||||
public Task<Card?> FindByCardId(string cardId)
|
||||
{
|
||||
return _context.Cards.Include(x => x.User).FirstOrDefaultAsync(c => c.RawId == cardId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using Server.Attributes;
|
||||
using Server.Handlers;
|
||||
using System.Xml.Linq;
|
||||
using Abstractions.Handlers;
|
||||
|
||||
namespace Server.Services;
|
||||
|
||||
public class HandlerService(IServiceScopeFactory serviceScopeFactory, ILogger<HandlerService> logger) : IHandlerService
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory = serviceScopeFactory;
|
||||
private readonly ILogger<HandlerService> _logger = logger;
|
||||
|
||||
public List<Type> Handlers { get; set; } = [];
|
||||
|
||||
public async Task<XDocument> Handle(string model, string module, string method, XDocument body)
|
||||
{
|
||||
foreach(var handler in Handlers)
|
||||
{
|
||||
//Module and service are on the attribute
|
||||
var handlerAttribute = handler.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(HandlerAttribute));
|
||||
|
||||
if(handlerAttribute is null)
|
||||
{
|
||||
var response = await HandleInheritanceClass(handler, model, module, method, body);
|
||||
|
||||
if(response is not null)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributeModule = handlerAttribute.ConstructorArguments[0].Value!.ToString();
|
||||
var attributeMethod = handlerAttribute.ConstructorArguments[1].Value!.ToString();
|
||||
|
||||
if (attributeModule != module || attributeMethod != method) continue;
|
||||
await using var scope = _serviceScopeFactory.CreateAsyncScope();
|
||||
|
||||
// Body param is optional, so check for it
|
||||
var requiresXDocumentConstructor = handler.GetConstructors()
|
||||
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
|
||||
var handlerInstance = requiresXDocumentConstructor
|
||||
? (IHandler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler, body)
|
||||
: (IHandler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler);
|
||||
|
||||
return await handlerInstance.HandleAsync(model);
|
||||
}
|
||||
|
||||
//If no handler is found return an empty document
|
||||
_logger.LogWarning($"No handler found for {model}/{module}/{method}");
|
||||
|
||||
return new XDocument();
|
||||
}
|
||||
|
||||
private async Task<XDocument?> HandleInheritanceClass(Type handler, string model, string module, string method, XDocument body)
|
||||
{
|
||||
await using var scope = _serviceScopeFactory.CreateAsyncScope();
|
||||
|
||||
bool requiredXdocumentConstructor = handler.GetConstructors()
|
||||
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
|
||||
|
||||
Handler handlerInstance = requiredXdocumentConstructor
|
||||
? (Handler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler, body)
|
||||
: (Handler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler);
|
||||
|
||||
try
|
||||
{
|
||||
var configureMethod = handler.GetMethod("Configure");
|
||||
configureMethod?.Invoke(handlerInstance, null);
|
||||
}
|
||||
catch(NotImplementedException e)
|
||||
{
|
||||
_logger.LogError(e, "Configure method not implemented for {Handler}", handler.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
var modelParts = model.Split(':');
|
||||
|
||||
var handlerModule = handlerInstance.HandlerModule;
|
||||
var handlerMethod = handlerInstance.HandlerMethod;
|
||||
var handlerGameCode = handlerInstance.HandlerGameCode;
|
||||
var handlerMinVer = handlerInstance.HandlerMinVer;
|
||||
var handlerMaxVer = handlerInstance.HandlerMaxVer;
|
||||
|
||||
if(string.IsNullOrEmpty(handlerModule))
|
||||
{
|
||||
_logger.LogError("Module not set for {Handler}", handler.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
if(string.IsNullOrEmpty(handlerMethod))
|
||||
{
|
||||
_logger.LogError("Method not set for {Handler}", handler.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(handlerGameCode))
|
||||
{
|
||||
if(handlerGameCode != modelParts[0])
|
||||
return null;
|
||||
}
|
||||
|
||||
var version = string.Join(string.Empty, modelParts.Skip(4));
|
||||
|
||||
if(!string.IsNullOrEmpty(handlerMinVer))
|
||||
{
|
||||
var parsedVersion = int.Parse(version);
|
||||
var parsedMinVer = int.Parse(handlerMinVer);
|
||||
|
||||
if(parsedVersion < parsedMinVer)
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(handlerMaxVer))
|
||||
{
|
||||
var parsedVersion = int.Parse(version);
|
||||
var parsedMaxVer = int.Parse(handlerMaxVer);
|
||||
if(parsedVersion > parsedMaxVer)
|
||||
return null;
|
||||
}
|
||||
|
||||
if(handlerModule != module || handlerMethod != method)
|
||||
return null;
|
||||
|
||||
var handleMethod = handlerInstance.GetType().GetMethod("Handle", [typeof(string)]);
|
||||
var handleAsyncMethod = handlerInstance.GetType().GetMethod("HandleAsync", [typeof(string)]);
|
||||
|
||||
var response = handleMethod?.DeclaringType != typeof(Handler)
|
||||
? handlerInstance.Handle(model)
|
||||
: handleAsyncMethod?.DeclaringType != typeof(Handler)
|
||||
? await handlerInstance.HandleAsync(model)
|
||||
: null;
|
||||
|
||||
if (response is not null) return response;
|
||||
_logger.LogError("Handle and HandleAsync not implemented for {Handler}", handler.Name);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
using Server.Entities;
|
||||
|
||||
namespace Server.Services
|
||||
{
|
||||
public interface ICardService
|
||||
{
|
||||
string ConvertUidToKonamiId(string uid);
|
||||
string ConvertKonamiIdToUid(string konamiId);
|
||||
Task<Card?> FindByKonamiId(string konamiId);
|
||||
Task<Card?> FindByCardId(string cardId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server.Services
|
||||
{
|
||||
public interface IHandlerService
|
||||
{
|
||||
public List<Type> Handlers { get; set; }
|
||||
Task<XDocument> Handle(string model, string module, string method, XDocument body);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Server.Services
|
||||
{
|
||||
public interface ISessionService
|
||||
{
|
||||
public void AddSession(string sessionId, string refId);
|
||||
string AddSession(string cardid);
|
||||
public (string sessionId, string refId) GetSession(string sessionId);
|
||||
public void removeSession(string sessionId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Server.Services
|
||||
{
|
||||
public interface IUserService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace Server.Services
|
||||
{
|
||||
public class SessionService : ISessionService
|
||||
{
|
||||
private readonly List<(string sessionId, string refId)> sessions = [];
|
||||
public void AddSession(string sessionId, string refId)
|
||||
{
|
||||
sessions.Add((sessionId, refId));
|
||||
}
|
||||
|
||||
public string AddSession(string cardid)
|
||||
{
|
||||
var sessionId = GenerateSessionId();
|
||||
sessions.Add((sessionId, cardid));
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public (string sessionId, string refId) GetSession(string sessionId)
|
||||
{
|
||||
return sessions.Find(s => s.sessionId == sessionId);
|
||||
}
|
||||
|
||||
public void removeSession(string sessionId)
|
||||
{
|
||||
sessions.Remove(sessions.Find(s => s.sessionId == sessionId));
|
||||
}
|
||||
|
||||
private string GenerateSessionId()
|
||||
{
|
||||
return Guid.NewGuid().ToString().Replace("-", "").ToUpper();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Server.Services
|
||||
{
|
||||
public class UserService: IUserService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Server.Utils;
|
||||
|
||||
public class DesEncryption(byte[] key)
|
||||
{
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
using var tripleDes = TripleDES.Create();
|
||||
|
||||
tripleDes.Key = key;
|
||||
tripleDes.Mode = CipherMode.CBC;
|
||||
tripleDes.Padding = PaddingMode.None;
|
||||
tripleDes.IV = new byte[8];
|
||||
|
||||
using var encryptor = tripleDes.CreateEncryptor();
|
||||
return encryptor.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data)
|
||||
{
|
||||
using var tripleDES = TripleDES.Create();
|
||||
|
||||
tripleDES.Key = key;
|
||||
tripleDES.Mode = CipherMode.CBC;
|
||||
tripleDES.Padding = PaddingMode.None;
|
||||
tripleDES.IV = new byte[8];
|
||||
|
||||
using var decryptor = tripleDES.CreateDecryptor();
|
||||
return decryptor.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
namespace Server.Utils;
|
||||
|
||||
public class LZ77
|
||||
{
|
||||
public static byte[] Decompress(byte[] data)
|
||||
{
|
||||
// init a buffer, size comes from eamuemu
|
||||
byte[] res = new byte[0x190000];
|
||||
// current data location
|
||||
int p = 0;
|
||||
// current output location
|
||||
int r = 0;
|
||||
// traceback location
|
||||
int t = 0;
|
||||
// bitmask location
|
||||
int b = 8; // read next bitmask byte on start
|
||||
byte mask = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
// read bitmask on block end
|
||||
if(b == 8)
|
||||
{
|
||||
mask = data[p];
|
||||
p += 1;
|
||||
b = 0;
|
||||
}
|
||||
// get mask for next byte
|
||||
if((mask & 1) == 1)
|
||||
{ // not coded
|
||||
// copy the byte from data to result
|
||||
res[r] = data[p];
|
||||
r += 1;
|
||||
p += 1;
|
||||
}
|
||||
else
|
||||
{ // coded
|
||||
// read descriptors
|
||||
int distance = data[p];
|
||||
int count = data[p + 1];
|
||||
// EOF mark
|
||||
if(distance == 0 && count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
p += 2;
|
||||
// shift to correct location
|
||||
distance <<= 4;
|
||||
distance |= count >> 4;
|
||||
count = (count & 0x0F) + 3;
|
||||
// copy earlier result bytes to the end
|
||||
t = r - distance; // initialize traceback location
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
res[r] = t < 0 ? (byte)0x00 : res[t];
|
||||
r += 1;
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
// shift mask
|
||||
mask >>= 1;
|
||||
b += 1;
|
||||
}
|
||||
// r = result length
|
||||
byte[] output = new byte[r];
|
||||
Array.Copy(res, output, r);
|
||||
return output;
|
||||
}
|
||||
|
||||
public static byte[] CompressEmpty(byte[] data)
|
||||
{
|
||||
byte[] res = new byte[data.Length + data.Length / 8 + 3];
|
||||
int p = 0;
|
||||
for(int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if(i % 8 == 0)
|
||||
{
|
||||
if(data.Length - i < 8)
|
||||
{
|
||||
res[p] = (byte)(Math.Pow(2, data.Length - i) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
res[p] = 255;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
res[p] = data[i];
|
||||
p += 1;
|
||||
}
|
||||
res[p] = 0;
|
||||
res[p + 1] = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Utils
|
||||
{
|
||||
public class RC4
|
||||
{
|
||||
public static string Encrypt(string key, string data)
|
||||
{
|
||||
Encoding unicode = Encoding.Unicode;
|
||||
|
||||
return Convert.ToBase64String(Encrypt(unicode.GetBytes(key), unicode.GetBytes(data)));
|
||||
}
|
||||
|
||||
public static string Decrypt(string key, string data)
|
||||
{
|
||||
Encoding unicode = Encoding.Unicode;
|
||||
|
||||
return unicode.GetString(Encrypt(unicode.GetBytes(key), Convert.FromBase64String(data)));
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(byte[] key, byte[] data)
|
||||
{
|
||||
return EncryptOutput(key, data).ToArray();
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] key, byte[] data)
|
||||
{
|
||||
return EncryptOutput(key, data).ToArray();
|
||||
}
|
||||
|
||||
private static byte[] InitializeKeyStream(byte[] key)
|
||||
{
|
||||
byte[] keyStream = Enumerable.Range(0, 256)
|
||||
.Select(i => (byte)i)
|
||||
.ToArray();
|
||||
|
||||
for(int keyStreamIndex = 0, keyIndex = 0; keyStreamIndex < 256; keyStreamIndex++)
|
||||
{
|
||||
keyIndex = (keyIndex + key[keyStreamIndex % key.Length] + keyStream[keyStreamIndex]) & 255;
|
||||
|
||||
Swap(keyStream, keyStreamIndex, keyIndex);
|
||||
}
|
||||
|
||||
return keyStream;
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
|
||||
{
|
||||
byte[] keyStream = InitializeKeyStream(key);
|
||||
|
||||
int keyStreamIndex = 0;
|
||||
int keyIndex = 0;
|
||||
|
||||
return data.Select((dataByte) =>
|
||||
{
|
||||
keyStreamIndex = (keyStreamIndex + 1) & 255;
|
||||
keyIndex = (keyIndex + keyStream[keyStreamIndex]) & 255;
|
||||
|
||||
Swap(keyStream, keyStreamIndex, keyIndex);
|
||||
|
||||
return (byte)(dataByte ^ keyStream[(keyStream[keyStreamIndex] + keyStream[keyIndex]) & 255]);
|
||||
});
|
||||
}
|
||||
|
||||
private static void Swap(byte[] keyStream, int firstIndex, int secondIndex) => (keyStream[secondIndex], keyStream[firstIndex]) = (keyStream[firstIndex], keyStream[secondIndex]);
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user