Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows #93

Merged
merged 24 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
57c2e6a
Added script to generate cert for windows
minhnhatnoe May 12, 2023
d24a3fe
Script for build
minhnhatnoe May 12, 2023
0eaf19c
Use filepath and os.remove to remove leftover generated files
minhnhatnoe May 12, 2023
89c9d64
A barely running version for windows
minhnhatnoe May 12, 2023
5a27de5
Extend sandbox choices
minhnhatnoe May 14, 2023
197d758
Print signal on abort
minhnhatnoe May 14, 2023
3142d3e
Remove {} in main.go switch case
minhnhatnoe May 15, 2023
b8e88c6
Panic if contesttype is invalid, not sure how it can be done but still
minhnhatnoe May 15, 2023
67d0412
use switch case for contesttype in scoreboard
minhnhatnoe May 16, 2023
8af4616
Leave VerdictIsInQueue in pkg worker for readability
minhnhatnoe May 16, 2023
c2913f6
Move position of Verdict constants
minhnhatnoe May 16, 2023
5e165f2
More detailed comment for the CA server
minhnhatnoe May 16, 2023
d88f55e
Fix grammar error
minhnhatnoe May 17, 2023
91d8be3
Align equal sign for VerdictIsInQueue
minhnhatnoe May 17, 2023
8292d34
Change powershell script to changes made at upstream
minhnhatnoe May 17, 2023
dcd6ddb
Fix grammar error
minhnhatnoe May 17, 2023
ac473b7
Formatting
natsukagami May 17, 2023
6332ca7
Move verdictisinqueue out of the query
minhnhatnoe May 18, 2023
f8f7bd3
Simpler log for undetected contest type
minhnhatnoe May 18, 2023
982e736
Revert capitalization of logs
minhnhatnoe May 18, 2023
5e5b338
Minor fixes
minhnhatnoe May 18, 2023
054df8c
Undo TODOs
minhnhatnoe May 20, 2023
910dadc
Update README.md
minhnhatnoe May 26, 2023
7693581
Merge branch 'master' into windows
natsukagami May 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ kjudge.db.bak
kjudge.db-*

/kjudge
/kjudge.exe
/templates
/keys
/embed/templates
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Usage of ./kjudge:

## Build Instructions

Warning: Windows support for kjudge is a WIP (and by that we mean machine-wrecking WIP). Run at your own risk.

External Dependencies:

```yaml
Expand Down
13 changes: 8 additions & 5 deletions cmd/kjudge/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

var (
dbfile = flag.String("file", "kjudge.db", "Path to the database file.")
sandboxImpl = flag.String("sandbox", "isolate", "The sandbox implementation to be used (isolate, raw). If anything other than 'raw' is given, isolate is used.")
sandboxImpl = flag.String("sandbox", "isolate", "The sandbox implementation to be used (isolate, raw). Defaults to isolate.")
port = flag.Int("port", 8088, "The port for the server to listen on.")

httpsDir = flag.String("https", "", "Path to the directory where the HTTPS private key (kjudge.key) and certificate (kjudge.crt) is located. If omitted or empty, HTTPS is disabled.")
Expand All @@ -34,11 +34,14 @@ func main() {
defer db.Close()

var sandbox worker.Sandbox
if *sandboxImpl == "raw" {
switch *sandboxImpl {
case "raw":
log.Println("'raw' sandbox selected. WE ARE NOT RESPONSIBLE FOR ANY BREAKAGE CAUSED BY FOREIGN CODE.")
sandbox = &raw.Sandbox{}
} else {
case "isolate":
sandbox = isolate.New()
default:
log.Fatalf("Sandbox %s doesn't exists or not yet implemented.", *sandboxImpl)
}

// Start the queue
Expand All @@ -58,9 +61,9 @@ func main() {
go queue.Start()
go startServer(server)

<-stop
received_signal := <-stop

log.Println("Shutting down")
log.Printf("Shutting down on receiving %s", received_signal)
}

func startServer(server *server.Server) {
Expand Down
4 changes: 2 additions & 2 deletions db/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"database/sql"
"io/fs"
"log"
"path"
"path/filepath"
"regexp"
"sort"

Expand Down Expand Up @@ -44,7 +44,7 @@ func (db *DB) migrate() error {

// Do migrations one by one
for _, name := range versions {
sqlFile := path.Join(assetsSql, name+".sql")
sqlFile := filepath.Join(assetsSql, name+".sql")
file, err := fs.ReadFile(embed.Content, sqlFile)
if err != nil {
return errors.Wrapf(err, "File %s", sqlFile)
Expand Down
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"test": "echo No tests... yet",
"fmt": "prettier \"css/**/*\" \"ts/**/*\" \"*.json\" \"*.js\"",
"dev": "parcel watch \"html/**/*.html\"",
"build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\""
"build": "mkdir -p ../embed/templates && rm -rf ../embed/templates/* && parcel build --no-source-maps --no-cache \"html/**/*.html\"",
"build:windows": "pwsh --command ../scripts/windows/frontend_build.ps1"
},
"alias": {
"react": "preact/compat",
Expand Down
19 changes: 16 additions & 3 deletions models/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"text/template"
Expand Down Expand Up @@ -331,14 +332,26 @@ func init() {
template.Must(t.Parse(FileTemplate))
}

func removeLeftoverGeneratedFiles() {
files, err := filepath.Glob("models/*_generated.go")
if err != nil {
log.Fatal(err)
}

for _, file := range files {
if err := os.Remove(file); err != nil {
log.Fatal(err)
}
}
}

func main() {
var tables TomlTables
if _, err := toml.DecodeFile("models/models.toml", &tables); err != nil {
log.Fatal(err)
}
if err := exec.Command("rm", "-fv", "models/*_generated.go").Run(); err != nil {
log.Fatal(err)
}
removeLeftoverGeneratedFiles()

files := []string{"-w"} // This is actually goimports's parameters.
for name, fields := range tables {
table := TableFromToml(tables, name, fields)
Expand Down
2 changes: 1 addition & 1 deletion models/rejudge.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func batchScoreJobs(subIDs ...int) []*Job {

// Remove the submission's `score`, `penalty` and `verdict`.
func resetScore(db db.DBContext, subIDs ...int) error {
query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = "..." WHERE id IN (?)`, subIDs)
query, params, err := sqlx.In(`UPDATE submissions SET score = NULL, penalty = NULL, verdict = ? WHERE id IN (?)`, VerdictIsInQueue, subIDs)
if err != nil {
return errors.WithStack(err)
}
Expand Down
8 changes: 6 additions & 2 deletions models/scoreboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/csv"
"fmt"
"io"
"log"
"sort"
"time"

Expand Down Expand Up @@ -134,7 +135,8 @@ func (s *Scoreboard) JSON() JSONScoreboard {
// Returns (comparison, is it just tie-breaking)
func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j int) (bool, bool) {
a, b := userResult[i], userResult[j]
if contestType == ContestTypeWeighted {
switch contestType {
case ContestTypeWeighted:
// sort based on totalScore if two users have same totalScore sort based on totalPenalty in an ascending order
if a.TotalScore != b.TotalScore {
return a.TotalScore > b.TotalScore, false
Expand All @@ -143,7 +145,7 @@ func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j
return a.TotalPenalty < b.TotalPenalty, false
}
return a.User.ID < b.User.ID, true
} else {
case ContestTypeUnweighted:
// sort based on solvedProblems if two users have same solvedProblems sort based on totalPenalty in an ascending order
if a.SolvedProblems != b.SolvedProblems {
return a.SolvedProblems > b.SolvedProblems, false
Expand All @@ -153,6 +155,8 @@ func compareUserRanking(userResult []*UserResult, contestType ContestType, i, j
}
return a.User.ID < b.User.ID, true
}
log.Panicf("unexpected contest type %s", contestType)
return true, true
}

// Get scoreboard given problems and contest
Expand Down
7 changes: 7 additions & 0 deletions models/submissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ const (
LanguageRust Language = "rustc"
)

const (
VerdictCompileError = "Compile Error"
VerdictScored = "Scored"
VerdictAccepted = "Accepted"
VerdictIsInQueue = "..."
)

var availableLanguages []string

// LanguageByExt returns a language based on the file extension.
Expand Down
5 changes: 5 additions & 0 deletions scripts/windows/frontend_build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
$ErrorActionPreference = "Stop"

New-Item -Type Directory -Force ../embed/templates | Out-Null
Remove-Item -Recurse -Force ../embed/templates/*
parcel build --no-source-maps --no-cache "html/**/*.html"
100 changes: 100 additions & 0 deletions scripts/windows/gen_cert.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<#
.SYNOPSIS
Generate self-signed SSL certificate
.DESCRIPTION
cert generation environment variables:
- OPENSSL_PATH [openssl] Path to openssl.exe
- RSA_BITS [4096] Strength of the RSA key.
- CERT_C [JP] Certificate country code
- CERT_ST [Moonland] Certificate State
- CERT_L [Kagamitown] Certificate Locality
- CERT_O [nki inc.] Certificate Organization Name
- CERT_CN [kjudge] Certificate Common name
- CERT_EMAIL [[email protected]] Certificate Email address
- CERT_ALTNAMES [IP:127.0.0.1,DNS:localhost] A list of hosts that kjudge will be listening on, either by IP (as 'IP:1.2.3.4') or DNS (as 'DNS:google.com'), separated by ','"
.PARAMETER TargetDir
Target directory to export generated SSL certificate
#>

Param (
[Parameter(
Mandatory,
HelpMessage = "Target directory to export generated SSL certificate",
Position = 0
)] [System.IO.FileInfo] $TargetDir
)

# Break on first error
$ErrorActionPreference = "Stop"

$OPENSSL_PATH = $Env:OPENSSL_PATH ?? "openssl"
Write-Host "OpenSSL Path: $OPENSSL_PATH"

$CERT_C = $Env:CERT_C ?? "JP" # Country code
$CERT_ST = $Env:CERT_ST ?? "Moonland" # State
$CERT_L = $Env:CERT_L ?? "Kagamitown" # Locality
$CERT_O = $Env:CERT_O ?? "nki inc." # Organization Name
$CERT_CN = $Env:CERT_CN ?? "kjudge" # Common name
$CERT_EMAIL = $Env:CERT_EMAIL ?? "[email protected]" # Email address
$CERT_ALTNAMES = $Env:CERT_ALTNAMES ?? "IP:127.0.0.1,DNS:localhost" # Alt hosts

# All information
$CERT_SUBJ = "/C=$CERT_C/ST=$CERT_ST/L=$CERT_L/O=$CERT_O/CN=$CERT_CN/emailAddress=$CERT_EMAIL"
$CERT_EXT = "subjectAltName = $CERT_ALTNAMES"

$RSA_BITS = $Env:RSA_BITS ?? 4096 # RSA bits

# Paths
$ROOT_DIR = $TargetDir

$CERT_GPATH = [IO.Path]::Combine($ROOT_DIR, '.certs_generated')
$ROOT_KEY = [IO.Path]::Combine($ROOT_DIR, "root.key")
$ROOT_CERT = [IO.Path]::Combine($ROOT_DIR, "root.pem")

$KJUDGE_KEY = [IO.Path]::Combine($ROOT_DIR, "kjudge.key")
$KJUDGE_CERT = [IO.Path]::Combine($ROOT_DIR, "kjudge.crt")
$KJUDGE_CSR = [IO.Path]::Combine($ROOT_DIR, "kjudge.csr")

Write-Host "Key info:"
Write-Host "- Country code = $CERT_C"
Write-Host "- State = $CERT_ST"
Write-Host "- Locality = $CERT_L"
Write-Host "- Organization Name = $CERT_O"
Write-Host "- Common name = $CERT_CN"
Write-Host "- Email address = $CERT_EMAIL"
Write-Host "- Alt hosts = $CERT_ALTNAMES"

Function Build-Key {
If ([System.IO.File]::Exists([IO.Path]::Combine($ROOT_DIR, ".certs_generated"))){
Write-Host "Certificate has already been generated."
return 0
}
Write-Host "Generating root private key to $ROOT_KEY"
openssl genrsa -out "$ROOT_KEY" "$RSA_BITS"

Write-Host "Generating a root certificate authority to $ROOT_CERT"
openssl req -x509 -new -key "$ROOT_KEY" -days 1285 -out "$ROOT_CERT" `
-subj "$CERT_SUBJ"

Write-Host "Generating a sub-key for kjudge to $KJUDGE_KEY"
openssl genrsa -out "$KJUDGE_KEY" "$RSA_BITS"

Write-Host "Generating a certificate signing request to $KJUDGE_CSR"
openssl req -new -key "$KJUDGE_KEY" -out "$KJUDGE_CSR" `
-subj "$CERT_SUBJ" -addext "$CERT_EXT"

Write-Host "Generating a certificate signature to $KJUDGE_CERT"
Write-Output "[v3_ca]\n%s\n" "$CERT_EXT" | openssl x509 -req -days 730 `
-in "$KJUDGE_CSR" `
-CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial `
-extensions v3_ca -extfile - `
-out "$KJUDGE_CERT"

Write-Host "Certificate generation complete."
Out-File -FilePath "$CERT_GPATH"
}
Build-Key

Write-Host "To re-generate the keys, delete " "$CERT_GPATH"
Write-Host "Please keep $ROOT_KEY and $KJUDGE_KEY secret, while distributing" `
"$ROOT_CERT as the certificate authority."
8 changes: 8 additions & 0 deletions scripts/windows/generate.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$ErrorActionPreference = "Stop"

Set-Location .\frontend
yarn
yarn run --prod build:windows
Set-Location ..

go generate
6 changes: 6 additions & 0 deletions scripts/windows/production_build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$ErrorActionPreference = "Stop"

& "scripts\windows\generate.ps1"

# Build
go build -tags "production" -o kjudge.exe cmd/kjudge/main.go
3 changes: 1 addition & 2 deletions server/admin/submission.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/natsukagami/kjudge/db"
"github.com/natsukagami/kjudge/models"
"github.com/natsukagami/kjudge/server/httperr"
"github.com/natsukagami/kjudge/worker"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -104,7 +103,7 @@ func (g *Group) SubmissionVerdictGet(c echo.Context) error {
if err != nil {
return err
}
if ctx.Submission.Verdict == "..." || ctx.Submission.Verdict == worker.VerdictCompileError {
if ctx.Submission.Verdict == models.VerdictIsInQueue || ctx.Submission.Verdict == models.VerdictCompileError {
return c.JSON(http.StatusOK, map[string]interface{}{
"verdict": ctx.Submission.Verdict,
})
Expand Down
2 changes: 1 addition & 1 deletion server/contests/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (g *Group) SubmitPost(c echo.Context) error {
Source: source,
Language: lang,
SubmittedAt: now,
Verdict: "...",
Verdict: models.VerdictIsInQueue,
}

if err := sub.Write(tx); err != nil {
Expand Down
3 changes: 1 addition & 2 deletions server/contests/submission.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/natsukagami/kjudge/db"
"github.com/natsukagami/kjudge/models"
"github.com/natsukagami/kjudge/server/httperr"
"github.com/natsukagami/kjudge/worker"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -111,7 +110,7 @@ func (g *Group) SubmissionVerdictGet(c echo.Context) error {
if err != nil {
return err
}
if ctx.Submission.Verdict == "..." || ctx.Submission.Verdict == worker.VerdictCompileError {
if ctx.Submission.Verdict == models.VerdictIsInQueue || ctx.Submission.Verdict == models.VerdictCompileError {
return c.JSON(http.StatusOK, map[string]interface{}{
"verdict": ctx.Submission.Verdict,
})
Expand Down
4 changes: 2 additions & 2 deletions server/root_ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/pkg/errors"
)

// ServeHTTPRootCA starts a HTTP server running on `address`
// serving the root CA from "/ca". It rejects all other requests.
// ServeHTTPRootCA starts a HTTP server running on `address` serving the .pem file at
// rootCA, serving the root CA from "/ca". It rejects all other requests.
func (s *Server) ServeHTTPRootCA(address, rootCA string) error {
if stat, err := os.Stat(rootCA); err != nil {
return errors.WithStack(err)
Expand Down
2 changes: 1 addition & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/pkg/errors"
)

// Server this the root entry of the server.
// Server is the root entry of the server.
type Server struct {
db *db.DB
echo *echo.Echo
Expand Down
Loading