Compare commits
5 Commits
d6fb612475
...
c0a632a4c6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0a632a4c6 | ||
|
|
085543b0f1 | ||
|
|
1fd431ba76 | ||
|
|
268a427172 | ||
|
|
620aaf6827 |
@@ -12,6 +12,12 @@
|
||||
- [opus-1.6.1](https://opus-codec.org/release/stable/2026/01/14/libopus-1_6_1.html)
|
||||
- [libpeconv c7d1e48](https://github.com/hasherezade/libpeconv)
|
||||
|
||||
## execution
|
||||
|
||||
- [MemoryModule](https://github.com/fancycode/MemoryModule.git)
|
||||
- [sRDI](https://github.com/Drewsif/sRDI.git)
|
||||
- [pe_to_shellcode](https://github.com/hasherezade/pe_to_shellcode.git)
|
||||
|
||||
## *Note*
|
||||
|
||||
The proper operation of the program depends on the above library files.
|
||||
|
||||
279
LICENSE-THIRD-PARTY.txt
Normal file
279
LICENSE-THIRD-PARTY.txt
Normal file
@@ -0,0 +1,279 @@
|
||||
THIRD-PARTY SOFTWARE NOTICES AND LICENSES
|
||||
|
||||
This document contains intellectual property notices and license information for
|
||||
third-party software components used in this product.
|
||||
|
||||
================================================================================
|
||||
SUMMARY OF LICENSE TYPES
|
||||
================================================================================
|
||||
The third-party components included in this software are governed by the following
|
||||
open-source licenses. For complete compliance, ensure that any modifications to
|
||||
LGPL and MPL covered components are made available under their respective terms,
|
||||
and this text file is distributed with your software product.
|
||||
|
||||
1. Zlib License
|
||||
- zlib v1.3.2
|
||||
2. BSD 3-Clause License
|
||||
- zstd v1.5.7
|
||||
- libyuv v190
|
||||
- jpeg (libjpeg-turbo) v3.1.1
|
||||
- opus-1.6.1
|
||||
3. BSD 2-Clause License
|
||||
- libpeconv c7d1e48
|
||||
- pe_to_shellcode
|
||||
4. MIT License
|
||||
- jsoncpp v1.9.6
|
||||
- sRDI
|
||||
5. GNU Lesser General Public License v2.1 (LGPL v2.1)
|
||||
- ffmpeg v7.1 (Compiled in shared, non-GPL mode)
|
||||
6. Mozilla Public License v2.0 (MPL 2.0)
|
||||
- MemoryModule
|
||||
|
||||
================================================================================
|
||||
1. zlib v1.3.2 (Zlib License)
|
||||
================================================================================
|
||||
Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
================================================================================
|
||||
2. zstd v1.5.7 (BSD 3-Clause License)
|
||||
================================================================================
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
3. libyuv v190 (BSD 3-Clause License)
|
||||
================================================================================
|
||||
Copyright 2011 The LibYuv Project Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Google nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
4. jpeg (libjpeg-turbo) v3.1.1 (BSD 3-Clause / IJG License)
|
||||
================================================================================
|
||||
Copyright (C) 2009-2024 D. R. Commander. All Rights Reserved.
|
||||
Copyright (C) 2015 Viktor Szathmáry. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
- Neither the name of the libjpeg-turbo Project nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
5. opus-1.6.1 (BSD 3-Clause License)
|
||||
================================================================================
|
||||
Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
|
||||
Jean-Marc Valin, Timothy B. Terriberry,
|
||||
CSIRO, Gregory Maxwell, Mark Borgerding,
|
||||
Erik de Castro Lopo
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.Org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
6. libpeconv c7d1e48 & pe_to_shellcode (BSD 2-Clause License)
|
||||
================================================================================
|
||||
Copyright (c) 2020, hasherezade
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
7. jsoncpp v1.9.6 (MIT License)
|
||||
================================================================================
|
||||
Copyright (c) 2007-2010 The JsonCpp Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
8. sRDI (MIT License)
|
||||
================================================================================
|
||||
Copyright (c) 2017 Drewsif
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
9. ffmpeg v7.1 (GNU Lesser General Public License v2.1)
|
||||
================================================================================
|
||||
This software uses libraries from the FFmpeg project (v7.1), licensed under the
|
||||
GNU Lesser General Public License (LGPL) version 2.1.
|
||||
FFmpeg is a trademark of Fabrice Bellard, originator of the FFmpeg project.
|
||||
|
||||
Our product links to FFmpeg dynamically as a shared library (.dll/.so/.dylib)
|
||||
and does NOT enable any GPL-licensed plugins (such as x264).
|
||||
|
||||
The source code of FFmpeg v7.1 can be obtained from the official FFmpeg
|
||||
website (https://ffmpeg.org). If you require the exact build script and build
|
||||
configuration used by our product to build the FFmpeg binary, please contact
|
||||
our open-source compliance team.
|
||||
|
||||
================================================================================
|
||||
10. MemoryModule (Mozilla Public License v2.0)
|
||||
================================================================================
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MemoryModule is Copyright (c) Joachim Bauch.
|
||||
|
||||
Under the terms of the MPL 2.0, you may distribute this component as part of
|
||||
your commercial/proprietary application without being required to open-source
|
||||
your own proprietary code, provided that:
|
||||
1. MemoryModule source files remain unmodified, or if modified, those modifications
|
||||
are made available under the MPL 2.0.
|
||||
2. Users are informed that MemoryModule is used and where they can find its source.
|
||||
@@ -1,6 +1,8 @@
|
||||
@echo off
|
||||
:: SimpleRemoter Quick Build Script
|
||||
:: Usage: build.cmd [release|debug] [x64|x86|all] [server|clean|publish]
|
||||
:: Usage: build.cmd [release|debug] [x64|x86|all] [server|clean|publish|go-server]
|
||||
:: go-server Build Go fallback server only -> Bin\YamaGo_x64.exe
|
||||
:: go-server publish Same, plus UPX --best compression
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
@@ -18,6 +20,7 @@ if /i "%~1"=="all" (set PLATFORM=all& shift& goto :parse_args)
|
||||
if /i "%~1"=="server" (set EXTRA_ARGS=!EXTRA_ARGS! -ServerOnly& shift& goto :parse_args)
|
||||
if /i "%~1"=="clean" (set EXTRA_ARGS=!EXTRA_ARGS! -Clean& shift& goto :parse_args)
|
||||
if /i "%~1"=="publish" (set EXTRA_ARGS=!EXTRA_ARGS! -Publish& shift& goto :parse_args)
|
||||
if /i "%~1"=="go-server" (set EXTRA_ARGS=!EXTRA_ARGS! -GoServer& shift& goto :parse_args)
|
||||
echo Unknown argument: %~1
|
||||
shift
|
||||
goto :parse_args
|
||||
|
||||
103
build.ps1
103
build.ps1
@@ -15,11 +15,110 @@ param(
|
||||
|
||||
[switch]$ServerOnly, # Only build main server (Yama), skip client projects
|
||||
[switch]$Clean, # Clean before build
|
||||
[switch]$Publish # Publish mode: rebuild all deps + x64 Release + UPX compress
|
||||
[switch]$Publish, # Publish mode: rebuild all deps + x64 Release + UPX compress
|
||||
[switch]$GoServer # Build Go fallback server (server/go) -> Bin/YamaGo_x64.exe
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$rootDir = $PSScriptRoot
|
||||
$binDir = Join-Path $rootDir "Bin"
|
||||
$upxPath = Join-Path $rootDir "server\2015Remote\res\3rd\upx.exe"
|
||||
|
||||
# Build Go fallback server. No-op (with warning) if Go compiler is not installed.
|
||||
# When -Compress is set, run UPX --best on the output (mirrors C++ publish flow).
|
||||
function Build-GoServer {
|
||||
param(
|
||||
[string]$Configuration,
|
||||
[switch]$Compress
|
||||
)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Building Go server (server/go)..." -ForegroundColor Magenta
|
||||
|
||||
$goCmd = Get-Command go -ErrorAction SilentlyContinue
|
||||
if (-not $goCmd) {
|
||||
Write-Host "WARNING: Go compiler not found in PATH. Skipping Go server build." -ForegroundColor Yellow
|
||||
Write-Host " Install from https://go.dev/dl/ and ensure 'go' is in PATH." -ForegroundColor DarkGray
|
||||
return $false
|
||||
}
|
||||
|
||||
Write-Host "Using Go: $($goCmd.Source)" -ForegroundColor Cyan
|
||||
|
||||
$goDir = Join-Path $rootDir "server\go"
|
||||
if (-not (Test-Path $goDir)) {
|
||||
Write-Host "ERROR: Go source directory not found at $goDir" -ForegroundColor Red
|
||||
return $false
|
||||
}
|
||||
|
||||
# Sync web assets (mirrors Makefile `sync` target — single source is server/web/index.html)
|
||||
$webSrc = Join-Path $rootDir "server\web\index.html"
|
||||
$webDstDir = Join-Path $goDir "web\assets"
|
||||
if (Test-Path $webSrc) {
|
||||
if (-not (Test-Path $webDstDir)) { New-Item -ItemType Directory -Path $webDstDir -Force | Out-Null }
|
||||
Copy-Item -Path $webSrc -Destination (Join-Path $webDstDir "index.html") -Force
|
||||
}
|
||||
|
||||
if (-not (Test-Path $binDir)) { New-Item -ItemType Directory -Path $binDir -Force | Out-Null }
|
||||
|
||||
$outFile = Join-Path $binDir "YamaGo_x64.exe"
|
||||
# Release strips debug info for smaller binary; Debug keeps symbols.
|
||||
$ldflags = if ($Configuration -eq "Debug") { "" } else { "-s -w" }
|
||||
|
||||
Push-Location $goDir
|
||||
try {
|
||||
$env:GOOS = "windows"
|
||||
$env:GOARCH = "amd64"
|
||||
if ($ldflags) {
|
||||
& go build -ldflags $ldflags -o $outFile ./cmd
|
||||
} else {
|
||||
& go build -o $outFile ./cmd
|
||||
}
|
||||
$code = $LASTEXITCODE
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if ($code -ne 0) {
|
||||
Write-Host "ERROR: Go build failed (exit $code)" -ForegroundColor Red
|
||||
return $false
|
||||
}
|
||||
|
||||
$size = (Get-Item $outFile).Length / 1MB
|
||||
Write-Host "OK: $outFile ($($size.ToString('F2')) MB)" -ForegroundColor Green
|
||||
|
||||
# In-place UPX compression. Failure is a warning, not an error — the
|
||||
# uncompressed binary is still usable, and UPX occasionally refuses on
|
||||
# certain PE sections.
|
||||
if ($Compress) {
|
||||
Write-Host ""
|
||||
Write-Host "UPX compressing Go server..." -ForegroundColor Magenta
|
||||
if (-not (Test-Path $upxPath)) {
|
||||
Write-Host "WARNING: UPX not found at $upxPath — skipping compression" -ForegroundColor Yellow
|
||||
} else {
|
||||
$sizeBefore = (Get-Item $outFile).Length / 1MB
|
||||
Write-Host " Before: $($sizeBefore.ToString('F2')) MB" -ForegroundColor DarkGray
|
||||
& $upxPath --best $outFile
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "WARNING: UPX compression failed, uncompressed binary kept" -ForegroundColor Yellow
|
||||
} else {
|
||||
$sizeAfter = (Get-Item $outFile).Length / 1MB
|
||||
$ratio = (1 - $sizeAfter / $sizeBefore) * 100
|
||||
Write-Host " After: $($sizeAfter.ToString('F2')) MB (-$($ratio.ToString('F1'))%)" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
# Go-only fast path: skip MSBuild entirely. -Publish here means "compress the
|
||||
# Go binary too" (not the full C++ publish flow).
|
||||
if ($GoServer) {
|
||||
$ok = Build-GoServer -Configuration $Config -Compress:$Publish
|
||||
if (-not $ok) { exit 1 }
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Find MSBuild (VS2019 or VS2022, including Insiders/Preview)
|
||||
# Order: Prefer installations with v142 toolset (VS2019) over VS2022 BuildTools
|
||||
$msBuildPaths = @(
|
||||
@@ -72,9 +171,7 @@ elseif ($msBuild -match "\\18\\") { $vsYear = "2019 Insiders" }
|
||||
|
||||
Write-Host "Using MSBuild: $msBuild" -ForegroundColor Cyan
|
||||
|
||||
$rootDir = $PSScriptRoot
|
||||
$slnFile = Join-Path $rootDir "YAMA.sln"
|
||||
$upxPath = Join-Path $rootDir "server\2015Remote\res\3rd\upx.exe"
|
||||
|
||||
# Publish mode overrides
|
||||
if ($Publish) {
|
||||
|
||||
@@ -5,7 +5,7 @@ extern "C" {
|
||||
#include <x264\x264.h>
|
||||
}
|
||||
|
||||
#define DISABLE_X264_FOR_TEST 0
|
||||
#include "common/config.h"
|
||||
|
||||
class CX264Encoder
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@@ -36,24 +37,20 @@ public:
|
||||
if (!filePath || !filePath[0])
|
||||
return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
#ifdef _MSC_VER
|
||||
if (fopen_s(&f, filePath, "r") != 0 || !f)
|
||||
std::ifstream f(filePath);
|
||||
if (!f.is_open())
|
||||
return false;
|
||||
#else
|
||||
f = fopen(filePath, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// 不再使用固定行缓冲:超过 4KB 的行(如团购授权数百个 IP 的列表)会被
|
||||
// fgets 拆成多段,第二段不带 '=' 会被 ParseLine 丢弃 → 显示截断。
|
||||
// std::getline 按行读 std::string,无长度上限。
|
||||
std::string currentSection;
|
||||
char line[4096];
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
ParseLine(line, currentSection);
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (!line.empty()) {
|
||||
ParseLine(&line[0], currentSection);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,13 +73,11 @@ public:
|
||||
while (lineEnd < end && *lineEnd != '\n' && *lineEnd != '\r')
|
||||
lineEnd++;
|
||||
|
||||
// 复制行内容
|
||||
// 不再限制行长度(原 4096 上限会悄无声息地丢弃长行)
|
||||
size_t lineLen = lineEnd - p;
|
||||
if (lineLen > 0 && lineLen < 4096) {
|
||||
char line[4096];
|
||||
memcpy(line, p, lineLen);
|
||||
line[lineLen] = '\0';
|
||||
ParseLine(line, currentSection);
|
||||
if (lineLen > 0) {
|
||||
std::string line(p, lineLen);
|
||||
ParseLine(&line[0], currentSection);
|
||||
}
|
||||
|
||||
// 跳过换行符
|
||||
@@ -100,24 +95,17 @@ public:
|
||||
if (!filePath || !filePath[0])
|
||||
return false;
|
||||
|
||||
FILE* f = nullptr;
|
||||
#ifdef _MSC_VER
|
||||
if (fopen_s(&f, filePath, "r") != 0 || !f)
|
||||
std::ifstream f(filePath);
|
||||
if (!f.is_open())
|
||||
return false;
|
||||
#else
|
||||
f = fopen(filePath, "r");
|
||||
if (!f)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
std::string currentSection;
|
||||
char line[4096];
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
ParseLine(line, currentSection);
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (!line.empty()) {
|
||||
ParseLine(&line[0], currentSection);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
6
common/config.h
Normal file
6
common/config.h
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
// 请设置为禁用,防止GPL开源传染性
|
||||
#define DISABLE_X264_FOR_TEST 0
|
||||
|
||||
// 请设置为禁用,防止GPL开源传染性
|
||||
#define DISABLE_FFMPEG_FOR_TEST 0
|
||||
@@ -208,9 +208,25 @@ public:
|
||||
|
||||
virtual std::string GetStr(const std::string& MainKey, const std::string& SubKey, const std::string& def = "")
|
||||
{
|
||||
char buf[4096] = { 0 }; // 增大缓冲区以支持较长的值(如 IP 列表)
|
||||
DWORD n = ::GetPrivateProfileStringA(MainKey.c_str(), SubKey.c_str(), def.c_str(), buf, sizeof(buf), m_IniFilePath);
|
||||
return std::string(buf);
|
||||
// 动态扩容读取:GetPrivateProfileStringA 在缓冲不够时会从中间截断,
|
||||
// 必须以"是否返回 bufSize-1"判断截断并翻倍重读,否则长值(如团购授权的
|
||||
// IP 列表)会被悄无声息地切断,且后续 read-modify-write 把截断结果写回时
|
||||
// 造成永久数据丢失。
|
||||
DWORD bufSize = 4096;
|
||||
const DWORD kMaxBufSize = 1024 * 1024; // 1MB 兜底,避免失控
|
||||
std::vector<char> buf;
|
||||
for (;;) {
|
||||
buf.assign(bufSize, 0);
|
||||
DWORD n = ::GetPrivateProfileStringA(MainKey.c_str(), SubKey.c_str(),
|
||||
def.c_str(), buf.data(), bufSize,
|
||||
m_IniFilePath);
|
||||
// 未截断:n < bufSize - 1
|
||||
if (n + 1 < bufSize || bufSize >= kMaxBufSize) {
|
||||
return std::string(buf.data(), n);
|
||||
}
|
||||
bufSize *= 2;
|
||||
if (bufSize > kMaxBufSize) bufSize = kMaxBufSize;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool SetStr(const std::string& MainKey, const std::string& SubKey, const std::string& Data)
|
||||
|
||||
@@ -228,16 +228,19 @@ private:
|
||||
}
|
||||
|
||||
// 后台线程处理日志
|
||||
// 退出语义:stop() 设 running=false 后,本线程必须把队列里**已入队**的日志
|
||||
// 全部刷盘再退出。否则进程死亡前最后几条 Mprintf(包括退出原因)会丢失。
|
||||
void processLogs()
|
||||
{
|
||||
threadRun = true;
|
||||
while (running) {
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(queueMutex);
|
||||
cv.wait(lock, [this]() {
|
||||
return !running || !logQueue.empty();
|
||||
});
|
||||
|
||||
while (running && !logQueue.empty()) {
|
||||
// drain:不带 running 判断,确保 stop() 时残留条目也写完
|
||||
while (!logQueue.empty()) {
|
||||
std::string logEntry = logQueue.front();
|
||||
logQueue.pop();
|
||||
lock.unlock();
|
||||
@@ -247,7 +250,9 @@ private:
|
||||
|
||||
lock.lock();
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
// 队列已空再决定要不要退出
|
||||
if (!running) break;
|
||||
}
|
||||
threadRun = false;
|
||||
}
|
||||
|
||||
@@ -786,8 +786,12 @@ static void daemonize()
|
||||
}
|
||||
|
||||
// 信号处理:收到 SIGTERM/SIGINT 时优雅退出
|
||||
// 注意:handler 内不能调 Mprintf(Logger 用 mutex/string/condvar,非 async-signal-safe),
|
||||
// 只在这里记 sig_atomic_t 标志位,main 退出循环后再补一行日志。
|
||||
static volatile sig_atomic_t g_lastSignal = 0;
|
||||
static void signalHandler(int sig)
|
||||
{
|
||||
g_lastSignal = sig;
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
}
|
||||
|
||||
@@ -1060,6 +1064,14 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 退出原因留痕:signal handler 不能直接打日志,在这里补一行。
|
||||
if (g_lastSignal != 0) {
|
||||
Mprintf(">>> Exit by signal %d (g_bExit=%d)\n",
|
||||
(int)g_lastSignal, (int)g_bExit);
|
||||
} else {
|
||||
Mprintf(">>> Exit normally (g_bExit=%d)\n", (int)g_bExit);
|
||||
}
|
||||
|
||||
Logger::getInstance().stop();
|
||||
removePidFile();
|
||||
return 0;
|
||||
|
||||
@@ -604,9 +604,13 @@ static void fillLoginInfo(LOGIN_INFOR& info)
|
||||
|
||||
// ============== Signal Handling ==============
|
||||
|
||||
// 注意:signal handler 内不能调 NSLog/Mprintf(NSLog 走 Foundation 锁,
|
||||
// Mprintf 走 Logger mutex/condvar),都不是 async-signal-safe。只在这里
|
||||
// 记 sig_atomic_t 标志位,main 退出循环后再补一行日志。
|
||||
static volatile sig_atomic_t g_lastSignal = 0;
|
||||
static void signalHandler(int sig)
|
||||
{
|
||||
NSLog(@"Received signal %d, shutting down...", sig);
|
||||
g_lastSignal = sig;
|
||||
g_running = false;
|
||||
g_bExit = S_CLIENT_EXIT; // 通知所有工作线程退出
|
||||
}
|
||||
@@ -934,6 +938,14 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 退出原因留痕:signal handler 不能直接打日志,在这里补一行。
|
||||
if (g_lastSignal != 0) {
|
||||
Mprintf(">>> Exit by signal %d (g_bExit=%d)\n",
|
||||
(int)g_lastSignal, (int)g_bExit);
|
||||
} else {
|
||||
Mprintf(">>> Exit normally (g_bExit=%d)\n", (int)g_bExit);
|
||||
}
|
||||
|
||||
NSLog(@"Shutting down...");
|
||||
|
||||
// Release power assertions
|
||||
@@ -944,6 +956,10 @@ int main(int argc, const char* argv[])
|
||||
// Display assertion is managed by ScreenHandler (released in stop())
|
||||
// powerActivity is automatically released when exiting @autoreleasepool
|
||||
(void)powerActivity; // Suppress unused variable warning
|
||||
|
||||
// 显式停止日志,确保上面 Mprintf 的退出原因落盘。
|
||||
// 不依赖 ~Logger() 的静态析构次序,避免后续新增日志相关静态对象时踩坑。
|
||||
Logger::getInstance().stop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -100,15 +100,17 @@ SNMatchResult ValidateLicenseSN(const std::string& licenseSN) {
|
||||
}
|
||||
return SNMatchResult::IPMismatch;
|
||||
} else {
|
||||
// Hardware binding: check if matches current device ID
|
||||
// Use GetHardwareID() to respect HWIDVersion (V1 or V2)
|
||||
std::string hardwareID = CMy2015RemoteDlg::GetHardwareID(0);
|
||||
// 哈希 SN:源头由本机 BindType 决定(硬件 ID 或 master/公网 IP)。
|
||||
// 接收机在生成 SN 时已配置好 BindType,这里直接读 settings 即可,
|
||||
// 不能硬编码 0,否则 IP 绑定的授权会被误判为硬件不匹配。
|
||||
std::string hardwareID = CMy2015RemoteDlg::GetHardwareID();
|
||||
std::string hashedID = hashSHA256(hardwareID);
|
||||
std::string currentDeviceID = getFixedLengthID(hashedID);
|
||||
if (licenseSN == currentDeviceID) {
|
||||
return SNMatchResult::Match;
|
||||
}
|
||||
return SNMatchResult::HardwareMismatch;
|
||||
int bindType = THIS_CFG.GetInt("settings", "BindType", 0);
|
||||
return (bindType == 1) ? SNMatchResult::IPMismatch : SNMatchResult::HardwareMismatch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,28 +8,81 @@
|
||||
#include "ToolbarDlg.h"
|
||||
#include "2015RemoteDlg.h"
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libyuv\libyuv.h"
|
||||
}
|
||||
|
||||
#if DISABLE_FFMPEG_FOR_TEST
|
||||
|
||||
#define AV_CODEC_ID_H264 27
|
||||
#define AVERROR(e) (-(e))
|
||||
|
||||
// 伪装不涉及内部成员直接访问的上下文指针
|
||||
typedef void AVCodecContext;
|
||||
typedef void AVCodec;
|
||||
|
||||
// 伪装 AVPacket 结构体,补全被主程序访问的 data 和 size 成员
|
||||
struct AVPacket {
|
||||
unsigned char* data;
|
||||
int size;
|
||||
long long pts;
|
||||
long long dts;
|
||||
int flags;
|
||||
};
|
||||
|
||||
// 伪装 AVFrame 结构体,补全被主程序访问的 data 和 linesize 成员
|
||||
struct AVFrame {
|
||||
unsigned char* data[8];
|
||||
int linesize[8];
|
||||
int width;
|
||||
int height;
|
||||
int format;
|
||||
};
|
||||
|
||||
// 使用 extern "C" __inline 或者是 inline 关键字,直接就地实现函数体
|
||||
extern "C" {
|
||||
__inline void av_frame_unref(AVFrame* frame) {
|
||||
if (frame) {
|
||||
for (int i = 0; i < 8; i++) { frame->data[i] = nullptr; frame->linesize[i] = 0; }
|
||||
}
|
||||
}
|
||||
__inline AVCodec* avcodec_find_decoder(int id) { return nullptr; }
|
||||
__inline void av_init_packet(AVPacket* pkt) { if (pkt) { pkt->data = nullptr; pkt->size = 0; } }
|
||||
__inline AVCodecContext* avcodec_alloc_context3(const AVCodec* codec) { return nullptr; }
|
||||
__inline void avcodec_free_context(AVCodecContext** avctx) { if (avctx) *avctx = nullptr; }
|
||||
__inline int avcodec_open2(AVCodecContext* avctx, const AVCodec* codec, void** options) { return -1; }
|
||||
__inline int avcodec_send_packet(AVCodecContext* avctx, const AVPacket* avpkt) { return -1; }
|
||||
__inline int avcodec_receive_frame(AVCodecContext* avctx, AVFrame* frame) { return -1; }
|
||||
__inline void avcodec_flush_buffers(AVCodecContext* avctx) { /* 空白实现 */ }
|
||||
}
|
||||
|
||||
#else
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec\avcodec.h"
|
||||
#include "libavutil\avutil.h"
|
||||
#include "libyuv\libyuv.h"
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
// https://github.com/Terodee/FFMpeg-windows-static-build/releases
|
||||
#pragma comment(lib,"ffmpeg/libavcodec.lib")
|
||||
#pragma comment(lib,"ffmpeg/libavutil.lib")
|
||||
#pragma comment(lib,"ffmpeg/libswresample.lib")
|
||||
|
||||
#pragma comment(lib,"libyuv/libyuv.lib")
|
||||
#else
|
||||
#pragma comment(lib,"x264/libx264_x64.lib")
|
||||
#pragma comment(lib,"libyuv/libyuv_x64.lib")
|
||||
// https://github.com/ShiftMediaProject/FFmpeg
|
||||
#pragma comment(lib,"ffmpeg/libavcodec_x64.lib")
|
||||
#pragma comment(lib,"ffmpeg/libavutil_x64.lib")
|
||||
#pragma comment(lib,"ffmpeg/libswresample_x64.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _WIN64
|
||||
#pragma comment(lib,"libyuv/libyuv.lib")
|
||||
#else
|
||||
#pragma comment(lib,"libyuv/libyuv_x64.lib")
|
||||
#endif
|
||||
|
||||
#pragma comment(lib, "Mfplat.lib")
|
||||
#pragma comment(lib, "Mfuuid.lib")
|
||||
|
||||
@@ -668,6 +668,15 @@ func main() {
|
||||
|
||||
log := logger.New(logCfg)
|
||||
|
||||
// Track env vars where we fell back to a built-in default. Printed once
|
||||
// at the end of startup so the operator sees what's in effect — vars the
|
||||
// operator explicitly set are NOT listed (they already know their value).
|
||||
type defaultedEnv struct{ name, value string }
|
||||
var defaultsUsed []defaultedEnv
|
||||
rememberDefault := func(name, value string) {
|
||||
defaultsUsed = append(defaultsUsed, defaultedEnv{name, value})
|
||||
}
|
||||
|
||||
// Create auth config
|
||||
authCfg := auth.DefaultConfig()
|
||||
// PwdHash can be set from environment or config file
|
||||
@@ -675,6 +684,7 @@ func main() {
|
||||
if authCfg.PwdHash == "" {
|
||||
// Default placeholder - should be configured in production
|
||||
authCfg.PwdHash = "61f04dd637a74ee34493fc1025de2c131022536da751c29e3ff4e9024d8eec43"
|
||||
rememberDefault("YAMA_PWDHASH", authCfg.PwdHash)
|
||||
}
|
||||
authCfg.SuperPass = os.Getenv("YAMA_PWD")
|
||||
|
||||
@@ -721,19 +731,23 @@ func main() {
|
||||
// Web user authenticator. Bootstrap admin from env var YAMA_WEB_ADMIN_PASS;
|
||||
// if unset, fall back to YAMA_PWD (same secret the TCP authorization uses)
|
||||
// so a single password env var is enough to bring up the whole stack.
|
||||
// If neither is set, no admin is registered and login will always fail —
|
||||
// the user must define a password before browsers can log in.
|
||||
// If neither is set we use a hard-coded "admin" default so the web UI is
|
||||
// usable out of the box — the startup banner surfaces this so operators
|
||||
// know to override it in any non-dev deployment.
|
||||
const defaultWebAdminPass = "admin"
|
||||
webAuth := wsauth.New()
|
||||
adminPass := os.Getenv("YAMA_WEB_ADMIN_PASS")
|
||||
if adminPass == "" {
|
||||
adminPass = os.Getenv("YAMA_PWD")
|
||||
}
|
||||
if adminPass != "" {
|
||||
webAuth.AddAdminFromPlainPassword("admin", adminPass)
|
||||
log.Info("Web admin user configured")
|
||||
} else {
|
||||
log.Warn("Neither YAMA_WEB_ADMIN_PASS nor YAMA_PWD is set; web login will be unavailable")
|
||||
usingDefaultWebPass := false
|
||||
if adminPass == "" {
|
||||
adminPass = defaultWebAdminPass
|
||||
rememberDefault("YAMA_WEB_ADMIN_PASS", defaultWebAdminPass)
|
||||
usingDefaultWebPass = true
|
||||
}
|
||||
webAuth.AddAdminFromPlainPassword("admin", adminPass)
|
||||
log.Info("Web admin user configured")
|
||||
|
||||
// Persistent users live in users.json next to the binary's working dir
|
||||
// — same default the C++ WebService uses (m_ConfigDir + "users.json").
|
||||
@@ -741,6 +755,7 @@ func main() {
|
||||
usersFile := os.Getenv("YAMA_USERS_FILE")
|
||||
if usersFile == "" {
|
||||
usersFile = "users.json"
|
||||
rememberDefault("YAMA_USERS_FILE", usersFile)
|
||||
}
|
||||
if err := webAuth.SetUsersFile(usersFile); err != nil {
|
||||
log.Warn("Failed to load %s: %v (continuing with admin only)", usersFile, err)
|
||||
@@ -849,10 +864,21 @@ func main() {
|
||||
fmt.Printf("Server started on port(s): %v\n", ports)
|
||||
if *httpPort != 0 {
|
||||
fmt.Printf("Web UI on http://localhost:%d/\n", *httpPort)
|
||||
if usingDefaultWebPass {
|
||||
fmt.Printf(" Default login: admin / %s (set YAMA_WEB_ADMIN_PASS to override)\n",
|
||||
defaultWebAdminPass)
|
||||
}
|
||||
}
|
||||
if licenseHTTP != nil {
|
||||
fmt.Printf("License Server on http://%s/license/{sign,heartbeat}\n", licAddr)
|
||||
}
|
||||
if len(defaultsUsed) > 0 {
|
||||
fmt.Println()
|
||||
fmt.Println("[!] Using built-in defaults (set the env var to override):")
|
||||
for _, d := range defaultsUsed {
|
||||
fmt.Printf(" %s = %s\n", d.name, d.value)
|
||||
}
|
||||
}
|
||||
fmt.Println("Logs are written to: logs/server.log")
|
||||
fmt.Println("Press Ctrl+C to stop...")
|
||||
|
||||
|
||||
@@ -7,8 +7,25 @@ import (
|
||||
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/hub"
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/protocol"
|
||||
"github.com/yuanyuanxiang/SimpleRemoter/server/go/wsauth"
|
||||
)
|
||||
|
||||
// rotateChallenge replaces the client's nonce with a fresh one and pushes a
|
||||
// {cmd:"challenge"} message so the browser updates its stored nonce. Called
|
||||
// after every login failure so a retry on the SAME WebSocket works without
|
||||
// the user having to refresh — the old nonce is still burned for replay
|
||||
// protection, but the client now has a usable new one.
|
||||
func (h *wsHub) rotateChallenge(c *wsClient) {
|
||||
n, err := wsauth.NewNonce()
|
||||
if err != nil {
|
||||
h.log.Error("nonce regen failed: %v", err)
|
||||
c.nonce = ""
|
||||
return
|
||||
}
|
||||
c.nonce = n
|
||||
c.queue([]byte(`{"cmd":"challenge","nonce":"` + n + `"}`))
|
||||
}
|
||||
|
||||
// dispatch routes one inbound message to its handler. The `raw` payload is
|
||||
// passed through so handlers can re-parse to their own shape.
|
||||
//
|
||||
@@ -125,10 +142,12 @@ func (h *wsHub) handleLogin(c *wsClient, raw []byte) {
|
||||
// with a uniform "credentials" error so the limit is not detectable.
|
||||
if !h.allowLoginByIP(c) || !h.allowLoginByUsername(in.Username) {
|
||||
h.log.Warn("ws login throttled: user=%s addr=%s", in.Username, c.addr)
|
||||
// Burn the challenge so the attacker can't immediately replay.
|
||||
c.nonce = ""
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
c.queue(mustJSON(map[string]any{"cmd": "login_result", "ok": false, "msg": "Invalid credentials"}))
|
||||
// Rotate the challenge: burns the previous nonce (replay protection)
|
||||
// AND hands the client a fresh one so the next attempt does not
|
||||
// require a page refresh.
|
||||
h.rotateChallenge(c)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,18 +155,18 @@ func (h *wsHub) handleLogin(c *wsClient, raw []byte) {
|
||||
// replays from a different connection can't reuse a captured response.
|
||||
if in.Nonce == "" || in.Nonce != c.nonce {
|
||||
c.queue(mustJSON(map[string]any{"cmd": "login_result", "ok": false, "msg": "Invalid challenge"}))
|
||||
h.rotateChallenge(c)
|
||||
return
|
||||
}
|
||||
|
||||
token, role, err := h.auth.VerifyLogin(in.Username, in.Response, in.Nonce)
|
||||
if err != nil {
|
||||
// Burn the challenge on failure too — forces a new round on retry.
|
||||
c.nonce = ""
|
||||
// Fixed delay on failure: makes online brute force impractical
|
||||
// even within the rate-limit budget, and erases the timing
|
||||
// difference between "wrong password" and "wrong nonce".
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
c.queue(mustJSON(map[string]any{"cmd": "login_result", "ok": false, "msg": "Invalid credentials"}))
|
||||
h.rotateChallenge(c)
|
||||
return
|
||||
}
|
||||
// Successful login: clear the per-IP/per-user budgets so a legitimate
|
||||
|
||||
Reference in New Issue
Block a user