14 Commits

Author SHA1 Message Date
fff4327007 revert: Let Current Waiting room become External Migration 2025-06-17 18:25:24 -04:00
6abbb3a323 feat: waiting room 2025-06-15 17:10:11 -04:00
50380ebc5c feat: waiting room 2025-06-14 21:11:50 -04:00
aa1e760a79 feat: waiting room check api 2025-06-09 18:48:48 -04:00
fcb08478d2 feat: use checker to manager key and session 2025-06-03 12:21:28 -04:00
c203cdf684 feat: Waiting room checker 2025-06-02 18:51:05 -04:00
42e9d6502d feat: config and checker of waiting room 2025-05-29 21:15:34 -04:00
1888f10b64 Merge pull request #3 from Rayzggz/bugfix/path-join
fix: File path error
2025-05-28 16:28:12 -04:00
d622430a6f fix: File path error
use filepath join to connect the config file path
2025-05-28 12:31:44 -04:00
2db26b78a0 Merge pull request #2 from Rayzggz/feature/merge-config-file
Feature/merge config file
2025-05-27 16:49:12 -04:00
6c340966a1 fix: wrong config file name 2025-05-27 16:21:57 -04:00
d47938ba22 fix: wrong config file name 2025-05-27 16:21:23 -04:00
bd4bbb01c1 feat: Use one yml file to config 2025-05-27 13:33:28 -04:00
87fb76f157 feat: Default Main config 2025-05-22 15:58:48 -04:00
11 changed files with 139 additions and 188 deletions

View File

@ -1,49 +0,0 @@
name: release-tag-version
on:
push:
tags:
- "v*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
docker:
runs-on: ubuntu-latest
permissions:
packages: write # to publish to ghcr.io
steps:
- uses: actions/checkout@v4
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
images: |-
ghcr.io/rayzggz/server_torii
# this will generate tags in the following format:
# latest
# 1
# 1.2
# 1.2.3
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build rootful docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -1,32 +0,0 @@
ARG ALPINE_VERSION=3.21
ARG GO_VERSION=1.23.5
ARG AUTHOR=Rayzggz
ARG SERVER_NAME=server_torii
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
ARG ALPINE_VERSION
ARG GO_VERSION
ARG SERVER_NAME
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
COPY . .
RUN set -eux; \
TARGETOS=${TARGETOS:-linux}; \
TARGETARCH=${TARGETARCH:-amd64}; \
echo "Building for TARGETOS=${TARGETOS} TARGETARCH=${TARGETARCH}"; \
go mod tidy; \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-s -w" -o /app/${SERVER_NAME}
FROM alpine:${ALPINE_VERSION} AS final
ARG SERVER_NAME
COPY --from=builder /app/${SERVER_NAME} /app/${SERVER_NAME}
EXPOSE 25555
ENTRYPOINT ["/app/server_torii"]

View File

@ -1,4 +0,0 @@
secret_key: "0378b0f84c4310279918d71a5647ba5d"
captcha_validate_time: 600
captcha_challenge_session_timeout: 120
hcaptcha_secret: ""

View File

@ -1,4 +0,0 @@
HTTPFloodSpeedLimit:
- "150/10s"
HTTPFloodSameURILimit:
- "50/10s"

View File

@ -0,0 +1,22 @@
CAPTCHA:
secret_key: "0378b0f84c4310279918d71a5647ba5d"
captcha_validate_time: 600
captcha_challenge_session_timeout: 120
hcaptcha_secret: ""
HTTPFlood:
HTTPFloodSpeedLimit:
- "150/10s"
HTTPFloodSameURILimit:
- "50/10s"
VerifyBot:
verify_google_bot: true
verify_bing_bot: true
verify_baidu_bot: true
verify_yandex_bot: true
verify_sogou_bot: true
verify_apple_bot: true
ExternalMigration:
enabled: false
redirect_url: "https://example.com/migration"
secret_key: "0378b0f84c4310279918d71a5647ba5d"
session_timeout: 1800

View File

@ -1,6 +0,0 @@
verify_google_bot: true
verify_bing_bot: true
verify_baidu_bot: true
verify_yandex_bot: true
verify_sogou_bot: true
verify_apple_bot: true

View File

@ -0,0 +1,21 @@
package check
import (
"server_torii/internal/action"
"server_torii/internal/config"
"server_torii/internal/dataType"
)
func ExternalMigration(reqData dataType.UserRequest, ruleSet *config.RuleSet, decision *action.Decision, sharedMem *dataType.SharedMemory) {
if !ruleSet.ExternalMigrationRule.Enabled {
decision.Set(action.Continue)
return
}
if !verifyClearanceCookie(reqData, *ruleSet) {
decision.SetResponse(action.Done, []byte("EXTERNAL"), genSessionID(reqData, *ruleSet))
return
}
decision.Set(action.Continue)
}

View File

@ -2,6 +2,7 @@ package config
import (
"bufio"
"fmt"
"gopkg.in/yaml.v3"
"net"
"os"
@ -27,6 +28,20 @@ type MainConfig struct {
// LoadMainConfig Read the configuration file and return the configuration object
func LoadMainConfig(basePath string) (*MainConfig, error) {
defaultCfg := MainConfig{
Port: "25555",
WebPath: "/torii",
RulePath: "/www/server_torii/config/rules",
ErrorPage: "/www/server_torii/config/error_page",
LogPath: "/www/server_torii/log/",
NodeName: "Server Torii",
ConnectingHostHeaders: []string{"Torii-Real-Host"},
ConnectingIPHeaders: []string{"Torii-Real-IP"},
ConnectingURIHeaders: []string{"Torii-Original-URI"},
ConnectingCaptchaStatusHeaders: []string{"Torii-Captcha-Status"},
}
exePath, err := os.Executable()
if err != nil {
return nil, err
@ -38,12 +53,12 @@ func LoadMainConfig(basePath string) (*MainConfig, error) {
data, err := os.ReadFile(configPath)
if err != nil {
return nil, err
return &defaultCfg, err
}
var cfg MainConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
return &defaultCfg, err
}
return &cfg, nil
@ -51,95 +66,115 @@ func LoadMainConfig(basePath string) (*MainConfig, error) {
// RuleSet stores all rules
type RuleSet struct {
IPAllowTrie *dataType.TrieNode
IPBlockTrie *dataType.TrieNode
URLAllowList *dataType.URLRuleList
URLBlockList *dataType.URLRuleList
CAPTCHARule *dataType.CaptchaRule
VerifyBotRule *dataType.VerifyBotRule
HTTPFloodRule *dataType.HTTPFloodRule
IPAllowTrie *dataType.TrieNode
IPBlockTrie *dataType.TrieNode
URLAllowList *dataType.URLRuleList
URLBlockList *dataType.URLRuleList
CAPTCHARule *dataType.CaptchaRule
VerifyBotRule *dataType.VerifyBotRule
HTTPFloodRule *dataType.HTTPFloodRule
ExternalMigrationRule *dataType.ExternalMigrationRule
}
// ruleSetWrapper
type ruleSetWrapper struct {
CAPTCHARule *dataType.CaptchaRule `yaml:"CAPTCHA"`
VerifyBotRule *dataType.VerifyBotRule `yaml:"VerifyBot"`
HTTPFloodRule httpFloodRuleWrapper `yaml:"HTTPFlood"`
ExternalMigrationRule *dataType.ExternalMigrationRule `yaml:"ExternalMigration"`
}
type httpFloodRuleWrapper struct {
HTTPFloodSpeedLimit []string `yaml:"HTTPFloodSpeedLimit"`
HTTPFloodSameURILimit []string `yaml:"HTTPFloodSameURILimit"`
}
// LoadRules Load all rules from the specified path
func LoadRules(rulePath string) (*RuleSet, error) {
rs := RuleSet{
IPAllowTrie: &dataType.TrieNode{},
IPBlockTrie: &dataType.TrieNode{},
URLAllowList: &dataType.URLRuleList{},
URLBlockList: &dataType.URLRuleList{},
CAPTCHARule: &dataType.CaptchaRule{},
VerifyBotRule: &dataType.VerifyBotRule{},
HTTPFloodRule: &dataType.HTTPFloodRule{},
IPAllowTrie: &dataType.TrieNode{},
IPBlockTrie: &dataType.TrieNode{},
URLAllowList: &dataType.URLRuleList{},
URLBlockList: &dataType.URLRuleList{},
CAPTCHARule: &dataType.CaptchaRule{},
VerifyBotRule: &dataType.VerifyBotRule{},
HTTPFloodRule: &dataType.HTTPFloodRule{},
ExternalMigrationRule: &dataType.ExternalMigrationRule{},
}
// Load IP Allow List
ipAllowFile := rulePath + "/IP_AllowList.conf"
ipAllowFile := filepath.Join(rulePath, "/IP_AllowList.conf")
if err := loadIPRules(ipAllowFile, rs.IPAllowTrie); err != nil {
return nil, err
}
// Load IP Block List
ipBlockFile := rulePath + "/IP_BlockList.conf"
ipBlockFile := filepath.Join(rulePath, "/IP_BlockList.conf")
if err := loadIPRules(ipBlockFile, rs.IPBlockTrie); err != nil {
return nil, err
}
// Load URL Allow List
urlAllowFile := rulePath + "/URL_AllowList.conf"
urlAllowFile := filepath.Join(rulePath, "/URL_AllowList.conf")
if err := loadURLRules(urlAllowFile, rs.URLAllowList); err != nil {
return nil, err
}
// Load URL Block List
urlBlockFile := rulePath + "/URL_BlockList.conf"
urlBlockFile := filepath.Join(rulePath, "/URL_BlockList.conf")
if err := loadURLRules(urlBlockFile, rs.URLBlockList); err != nil {
return nil, err
}
// Load CAPTCHA Rule
captchaFile := rulePath + "/CAPTCHA.yml"
if err := loadCAPTCHARule(captchaFile, rs.CAPTCHARule); err != nil {
return nil, err
}
// Load Verify Bot Rule
verifyBotFile := rulePath + "/VerifyBot.yml"
if err := loadVerifyBotRule(verifyBotFile, rs.VerifyBotRule); err != nil {
return nil, err
}
// Load HTTP Flood Rule
httpFloodFile := rulePath + "/HTTPFlood.yml"
if err := loadHTTPFloodRule(httpFloodFile, rs.HTTPFloodRule); err != nil {
return nil, err
YAMLFile := filepath.Join(rulePath, "Server.yml")
set, err := loadServerRules(YAMLFile, rs)
if err != nil {
return set, err
}
return &rs, nil
}
func loadCAPTCHARule(file string, rule *dataType.CaptchaRule) error {
data, err := os.ReadFile(file)
func loadServerRules(YAMLFile string, rs RuleSet) (*RuleSet, error) {
yamlData, err := os.ReadFile(YAMLFile)
if err != nil {
return err
if os.IsNotExist(err) {
return nil, fmt.Errorf("[ERROR] rules file %s does not exist: %w", YAMLFile, err)
} else {
return nil, fmt.Errorf("[ERROR] failed to read rules file %s: %w", YAMLFile, err)
}
}
if err := yaml.Unmarshal(data, &rule); err != nil {
return err
var wrapper ruleSetWrapper
if err := yaml.Unmarshal(yamlData, &wrapper); err != nil {
return nil, fmt.Errorf("[ERROR] failed to parse rules file %s: %w", YAMLFile, err)
}
return nil
}
func loadVerifyBotRule(file string, rule *dataType.VerifyBotRule) error {
data, err := os.ReadFile(file)
if err != nil {
return err
*rs.CAPTCHARule = *wrapper.CAPTCHARule
*rs.VerifyBotRule = *wrapper.VerifyBotRule
if wrapper.ExternalMigrationRule != nil {
*rs.ExternalMigrationRule = *wrapper.ExternalMigrationRule
}
if err := yaml.Unmarshal(data, &rule); err != nil {
return err
rs.HTTPFloodRule.HTTPFloodSpeedLimit = make(map[int64]int64)
rs.HTTPFloodRule.HTTPFloodSameURILimit = make(map[int64]int64)
for _, s := range wrapper.HTTPFloodRule.HTTPFloodSpeedLimit {
limit, seconds, err := utils.ParseRate(s)
if err != nil {
return nil, err
}
rs.HTTPFloodRule.HTTPFloodSpeedLimit[seconds] = limit
}
return nil
for _, s := range wrapper.HTTPFloodRule.HTTPFloodSameURILimit {
limit, seconds, err := utils.ParseRate(s)
if err != nil {
return nil, err
}
rs.HTTPFloodRule.HTTPFloodSameURILimit[seconds] = limit
}
return nil, nil
}
// loadIPRules read the IP rule file and insert the rules into the trie
@ -217,43 +252,3 @@ func loadURLRules(filePath string, list *dataType.URLRuleList) error {
return scanner.Err()
}
func loadHTTPFloodRule(file string, rule *dataType.HTTPFloodRule) error {
data, err := os.ReadFile(file)
if err != nil {
return err
}
type httpFloodRuleYAML struct {
HTTPFloodSpeedLimit []string `yaml:"HTTPFloodSpeedLimit"`
HTTPFloodSameURILimit []string `yaml:"HTTPFloodSameURILimit"`
}
var ymlRule httpFloodRuleYAML
err = yaml.Unmarshal(data, &ymlRule)
if err != nil {
return err
}
rule.HTTPFloodSpeedLimit = make(map[int64]int64)
rule.HTTPFloodSameURILimit = make(map[int64]int64)
for _, s := range ymlRule.HTTPFloodSpeedLimit {
limit, seconds, err := utils.ParseRate(s)
if err != nil {
return err
}
rule.HTTPFloodSpeedLimit[seconds] = limit
}
for _, s := range ymlRule.HTTPFloodSameURILimit {
limit, seconds, err := utils.ParseRate(s)
if err != nil {
return err
}
rule.HTTPFloodSameURILimit[seconds] = limit
}
return nil
}

View File

@ -31,6 +31,13 @@ type HTTPFloodRule struct {
HTTPFloodSameURILimit map[int64]int64
}
type ExternalMigrationRule struct {
Enabled bool `yaml:"enabled"`
RedirectUrl string `yaml:"redirect_url"`
SecretKey string `yaml:"secret_key"`
SessionTimeout int64 `yaml:"session_timeout"`
}
type SharedMemory struct {
HTTPFloodSpeedLimitCounter *Counter
HTTPFloodSameURILimitCounter *Counter

View File

@ -25,6 +25,7 @@ func CheckMain(w http.ResponseWriter, userRequestData dataType.UserRequest, rule
checkFuncs = append(checkFuncs, check.URLBlockList)
checkFuncs = append(checkFuncs, check.VerifyBot)
checkFuncs = append(checkFuncs, check.HTTPFlood)
checkFuncs = append(checkFuncs, check.ExternalMigration)
checkFuncs = append(checkFuncs, check.Captcha)
for _, checkFunc := range checkFuncs {

View File

@ -27,7 +27,7 @@ func main() {
// Load MainConfig
cfg, err := config.LoadMainConfig(basePath)
if err != nil {
log.Fatalf("Load config failed: %v", err)
log.Printf("[ERROR] Load config failed: %v. Using default config.", err)
}
// Load rules