Skip to content
Merged

Dev #158

Show file tree
Hide file tree
Changes from all commits
Commits
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
621 changes: 621 additions & 0 deletions .github/workflows/release.yml.bak

Large diffs are not rendered by default.

37 changes: 22 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.5.10"
version = "0.5.11"
license = "AGPL-3"
edition = "2024"
repository = "https://github.com/NodeSeekDev/NodeGet"
Expand Down Expand Up @@ -63,6 +63,7 @@ tower = { version = "0.5.3", default-features = false }
axum-server = { version = "0.8.0", features = ["tls-rustls-no-provider"] }
dhat = { version = "0.3.3"}
arc-swap = { version = "1.9", default-features = false }
portable-atomic = { version = "1.13.1", default-features = false, features = ["fallback"] }

# Internal crates
ng-core = { path = "crates/ng-core" }
Expand Down
78 changes: 61 additions & 17 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,61 @@
[target.arm-unknown-linux-gnueabi]
rustflags = ["-C", "link-arg=-latomic"]

[target.arm-unknown-linux-gnueabihf]
rustflags = ["-C", "link-arg=-latomic"]

[target.armv7-unknown-linux-gnueabi]
rustflags = ["-C", "link-arg=-latomic"]

[target.armv7-unknown-linux-gnueabihf]
rustflags = ["-C", "link-arg=-latomic"]

[target.armv7-unknown-linux-musleabi]
rustflags = ["-C", "link-arg=-latomic"]

[target.armv7-unknown-linux-musleabihf]
rustflags = ["-C", "link-arg=-latomic"]
## Android
#[target.x86_64-linux-android]
#build-std = true
#
#[target.i686-linux-android]
#build-std = true
#
#[target.aarch64-linux-android]
#build-std = true
#
#[target.arm-linux-androideabi]
#build-std = true
#
#[target.armv7-linux-androideabi]
#build-std = true
#
#[target.thumbv7neon-linux-androideabi]
#build-std = true
#
## ARM 老款 (tier 3):无预编译 std,必须从源码构建
#[target.armv5te-unknown-linux-gnueabi]
#build-std = true
#
#[target.armv5te-unknown-linux-musleabi]
#build-std = true
#
## 极老 x86 (tier 3)
#[target.i586-unknown-linux-gnu]
#build-std = true
#
#[target.i586-unknown-linux-musl]
#build-std = true
#
## 32 位 PowerPC (tier 3)
#[target.powerpc-unknown-linux-gnu]
#build-std = true
#
## MIPS 系列 (tier 3):无预编译 std,必须从源码构建
#[target.mips-unknown-linux-gnu]
#build-std = true
#
#[target.mips-unknown-linux-musl]
#build-std = true
#
#[target.mipsel-unknown-linux-gnu]
#build-std = true
#
#[target.mipsel-unknown-linux-musl]
#build-std = true
#
#[target.mips64-unknown-linux-gnuabi64]
#build-std = true
#
#[target.mips64-unknown-linux-muslabi64]
#build-std = true
#
#[target.mips64el-unknown-linux-gnuabi64]
#build-std = true
#
#[target.mips64el-unknown-linux-muslabi64]
#build-std = true
3 changes: 3 additions & 0 deletions crates/ng-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ uuid = { workspace = true }
rand = { workspace = true }
tracing = { workspace = true }

# 32 位平台兼容:portable-atomic 在不支持原生 64 位原子操作的平台提供回退实现
portable-atomic = { workspace = true }

# for-server / for-agent feature dependencies
libc = { version = "0.2.175", default-features = false, optional = true }

Expand Down
2 changes: 1 addition & 1 deletion crates/ng-core/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rand::distr::Alphanumeric;
use rand::{RngExt, rng};
use serde::Deserialize;
use serde::Serialize;
use std::sync::atomic::{AtomicI64, Ordering};
use portable_atomic::{AtomicI64, Ordering};

#[cfg(feature = "for-server")]
pub mod error_message;
Expand Down
29 changes: 21 additions & 8 deletions crates/ng-crontab/src/rpc/crontab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@ mod set_enable;

/// 校验 crontab 名称合法性。
///
/// 只允许字母、数字、下划线、短横线。禁止路径分隔符及控制字符。
/// 允许 Unicode 字母、数字、下划线、短横线(支持中文等多语言命名)。
/// 禁止路径分隔符、控制字符及可能造成问题的特殊符号。
fn validate_name(name: &str) -> anyhow::Result<()> {
if name.is_empty() {
return Err(ng_core::error::NodegetError::InvalidInput("name cannot be empty".to_owned()).into());
}
if name.len() > 128 {
if name.chars().count() > 128 {
return Err(ng_core::error::NodegetError::InvalidInput("name too long (max 128 chars)".to_owned()).into());
}
let valid = name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-');
let valid = name.chars().all(|c| {
// 允许:Unicode 字母/数字(含中文)、下划线、短横线
c.is_alphanumeric() || c == '_' || c == '-'
});
if !valid {
return Err(ng_core::error::NodegetError::InvalidInput(
"name contains invalid characters (only [A-Za-z0-9_-] are allowed)".to_owned(),
"name contains invalid characters (alphanumeric, underscore, hyphen allowed)".to_owned(),
)
.into());
}
Expand Down Expand Up @@ -208,6 +210,16 @@ mod tests {
assert!(validate_name(&name).is_ok());
}

#[test]
fn validate_name_accepts_chinese() {
assert!(validate_name("电信ping").is_ok());
}

#[test]
fn validate_name_accepts_mixed_chinese_ascii() {
assert!(validate_name("定时任务_1").is_ok());
}

// ── validate_name: empty ──────────────────────────────────────

#[test]
Expand Down Expand Up @@ -259,8 +271,9 @@ mod tests {
}

#[test]
fn validate_name_rejects_unicode() {
assert!(validate_name("定时任务").is_err());
fn validate_name_rejects_unicode_symbols() {
// Unicode 符号(非字母数字)仍应被拒绝
assert!(validate_name("任务❌").is_err());
}

#[test]
Expand Down
28 changes: 15 additions & 13 deletions crates/ng-token/src/super_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::hash_to_bytes;
/// - 错误:数据库插入失败(通常因 ID=1 唯一约束冲突)
async fn insert_new_super_token(
db: &sea_orm::DatabaseConnection,
) -> anyhow::Result<(String, String)> {
) -> Result<(String, String), sea_orm::DbErr> {
let token_key = generate_random_string(16);
let token_secret = generate_random_string(32);
let full_token = format!("{token_key}:{token_secret}");
Expand All @@ -50,12 +50,7 @@ async fn insert_new_super_token(
password_hash: Set(Some(password_hash)),
};

token::Entity::insert(super_token_model)
.exec(db)
.await
.map_err(|e| {
NodegetError::DatabaseError(format!("Failed to initialize super token: {e}"))
})?;
token::Entity::insert(super_token_model).exec(db).await?;

debug!(target: "token", "Super token inserted into database");
Ok((full_token, raw_password))
Expand All @@ -82,15 +77,22 @@ pub async fn generate_super_token() -> anyhow::Result<Option<(String, String)>>
}
Ok(Some(result))
}
Err(e) => {
// 判断是否为唯一约束冲突(SQLite 和 PostgreSQL 的错误消息不同)
let error_msg = format!("{e}");
if error_msg.contains("UNIQUE constraint failed") || error_msg.contains("duplicate key")
{
Err(db_err) => {
// 使用 SeaORM 的 sql_err() 精确判断唯一约束冲突,
// 不依赖错误消息字符串(PostgreSQL 中文 locale 下消息不含 "duplicate key")
let is_unique_violation = matches!(
db_err.sql_err(),
Some(sea_orm::SqlErr::UniqueConstraintViolation(_))
);

if is_unique_violation {
debug!(target: "token", "Super token already exists, skipping generation");
Ok(None)
} else {
Err(e)
Err(NodegetError::DatabaseError(format!(
"Failed to initialize super token: {db_err}"
))
.into())
}
}
}
Expand Down
Loading