feat: Add Gitea username integration, refactor password hashing with direct bcrypt, and remove frontend version displays.
This commit is contained in:
parent
bc1597a41d
commit
4d3761e0e0
|
|
@ -0,0 +1,34 @@
|
||||||
|
"""add gitea_username to user model
|
||||||
|
|
||||||
|
Revision ID: 08a73307418d
|
||||||
|
Revises: ecc7c0ff0957
|
||||||
|
Create Date: 2026-01-05 13:36:16.845876
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '08a73307418d'
|
||||||
|
down_revision = 'ecc7c0ff0957'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('users', sa.Column('gitea_username', sa.String(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('users', 'gitea_username')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,18 +1,10 @@
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import Any, Union
|
from typing import Any, Union
|
||||||
from jose import jwt
|
from jose import jwt
|
||||||
import bcrypt # Import first
|
import bcrypt
|
||||||
|
|
||||||
# MonkeyPatch passlib/bcrypt compatibility (passlib expects __about__)
|
|
||||||
if not hasattr(bcrypt, "__about__"):
|
|
||||||
from types import SimpleNamespace
|
|
||||||
bcrypt.__about__ = SimpleNamespace(__version__=bcrypt.__version__)
|
|
||||||
|
|
||||||
from passlib.context import CryptContext
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
||||||
|
|
||||||
ALGORITHM = settings.ALGORITHM
|
ALGORITHM = settings.ALGORITHM
|
||||||
|
|
||||||
def create_access_token(
|
def create_access_token(
|
||||||
|
|
@ -29,10 +21,36 @@ def create_access_token(
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||||
return pwd_context.verify(plain_password, hashed_password)
|
"""
|
||||||
|
Verify a password against a hash.
|
||||||
|
Explicitly truncate to 72 bytes to avoid bcrypt ValueError and maintain compatibility.
|
||||||
|
"""
|
||||||
|
if not plain_password or not hashed_password:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
password_bytes = plain_password.encode("utf-8")
|
||||||
|
if len(password_bytes) > 72:
|
||||||
|
password_bytes = password_bytes[:72]
|
||||||
|
|
||||||
|
return bcrypt.checkpw(
|
||||||
|
password_bytes,
|
||||||
|
hashed_password.encode("utf-8")
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
def get_password_hash(password: str) -> str:
|
def get_password_hash(password: str) -> str:
|
||||||
return pwd_context.hash(password)
|
"""
|
||||||
|
Generate a bcrypt hash of the password.
|
||||||
|
Explicitly truncate to 72 bytes for consistency.
|
||||||
|
"""
|
||||||
|
password_bytes = password.encode("utf-8")
|
||||||
|
if len(password_bytes) > 72:
|
||||||
|
password_bytes = password_bytes[:72]
|
||||||
|
|
||||||
|
salt = bcrypt.gensalt()
|
||||||
|
return bcrypt.hashpw(password_bytes, salt).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class User(Base):
|
||||||
role = Column(String, default="member")
|
role = Column(String, default="member")
|
||||||
github_username = Column(String, nullable=True)
|
github_username = Column(String, nullable=True)
|
||||||
gitlab_username = Column(String, nullable=True)
|
gitlab_username = Column(String, nullable=True)
|
||||||
|
gitea_username = Column(String, nullable=True)
|
||||||
|
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ class UserBase(BaseModel):
|
||||||
role: str = "member"
|
role: str = "member"
|
||||||
github_username: Optional[str] = None
|
github_username: Optional[str] = None
|
||||||
gitlab_username: Optional[str] = None
|
gitlab_username: Optional[str] = None
|
||||||
|
gitea_username: Optional[str] = None
|
||||||
|
|
||||||
class UserCreate(UserBase):
|
class UserCreate(UserBase):
|
||||||
email: EmailStr
|
email: EmailStr
|
||||||
|
|
|
||||||
|
|
@ -275,8 +275,8 @@ SYSTEM_RULE_SETS = [
|
||||||
"description": "基于 OWASP Top 10 2021 的安全审计规则集",
|
"description": "基于 OWASP Top 10 2021 的安全审计规则集",
|
||||||
"language": "all",
|
"language": "all",
|
||||||
"rule_type": "security",
|
"rule_type": "security",
|
||||||
"is_default": True,
|
"is_default": False,
|
||||||
"sort_order": 0,
|
"sort_order": 1,
|
||||||
"severity_weights": {"critical": 10, "high": 5, "medium": 2, "low": 1},
|
"severity_weights": {"critical": 10, "high": 5, "medium": 2, "low": 1},
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
|
|
@ -386,8 +386,8 @@ SYSTEM_RULE_SETS = [
|
||||||
"description": "通用代码质量检查规则集",
|
"description": "通用代码质量检查规则集",
|
||||||
"language": "all",
|
"language": "all",
|
||||||
"rule_type": "quality",
|
"rule_type": "quality",
|
||||||
"is_default": False,
|
"is_default": True,
|
||||||
"sort_order": 1,
|
"sort_order": 0,
|
||||||
"severity_weights": {"critical": 10, "high": 5, "medium": 2, "low": 1},
|
"severity_weights": {"critical": 10, "high": 5, "medium": 2, "low": 1},
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
|
|
@ -550,6 +550,11 @@ async def init_system_templates(db: AsyncSession) -> None:
|
||||||
)
|
)
|
||||||
db.add(template)
|
db.add(template)
|
||||||
logger.info(f"✓ 创建系统提示词模板: {template_data['name']}")
|
logger.info(f"✓ 创建系统提示词模板: {template_data['name']}")
|
||||||
|
else:
|
||||||
|
# 更新已存在的系统模板的默认状态和排序
|
||||||
|
existing.is_default = template_data.get("is_default", False)
|
||||||
|
existing.sort_order = template_data.get("sort_order", 0)
|
||||||
|
db.add(existing)
|
||||||
|
|
||||||
await db.flush()
|
await db.flush()
|
||||||
|
|
||||||
|
|
@ -599,6 +604,11 @@ async def init_system_rule_sets(db: AsyncSession) -> None:
|
||||||
db.add(rule)
|
db.add(rule)
|
||||||
|
|
||||||
logger.info(f"✓ 创建系统规则集: {rule_set_data['name']} ({len(rule_set_data.get('rules', []))} 条规则)")
|
logger.info(f"✓ 创建系统规则集: {rule_set_data['name']} ({len(rule_set_data.get('rules', []))} 条规则)")
|
||||||
|
else:
|
||||||
|
# 更新已存在的系统规则集的默认状态和排序
|
||||||
|
existing.is_default = rule_set_data.get("is_default", False)
|
||||||
|
existing.sort_order = rule_set_data.get("sort_order", 0)
|
||||||
|
db.add(existing)
|
||||||
|
|
||||||
await db.flush()
|
await db.flush()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,6 @@ export default function TerminalProgressDialog({
|
||||||
<Terminal className="w-5 h-5 text-primary" />
|
<Terminal className="w-5 h-5 text-primary" />
|
||||||
<div>
|
<div>
|
||||||
<span className="text-lg font-bold uppercase tracking-[0.15em] text-slate-800 dark:text-[#f0e6d3]">AUDIT_TERMINAL</span>
|
<span className="text-lg font-bold uppercase tracking-[0.15em] text-slate-800 dark:text-[#f0e6d3]">AUDIT_TERMINAL</span>
|
||||||
<span className="text-xs text-slate-500 dark:text-[#5a6577] ml-2 tracking-wider">v3.0</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export default function Account() {
|
||||||
phone: "",
|
phone: "",
|
||||||
github_username: "",
|
github_username: "",
|
||||||
gitlab_username: "",
|
gitlab_username: "",
|
||||||
|
gitea_username: "",
|
||||||
});
|
});
|
||||||
const [passwordForm, setPasswordForm] = useState({
|
const [passwordForm, setPasswordForm] = useState({
|
||||||
current_password: "",
|
current_password: "",
|
||||||
|
|
@ -60,6 +61,7 @@ export default function Account() {
|
||||||
phone: res.data.phone || "",
|
phone: res.data.phone || "",
|
||||||
github_username: res.data.github_username || "",
|
github_username: res.data.github_username || "",
|
||||||
gitlab_username: res.data.gitlab_username || "",
|
gitlab_username: res.data.gitlab_username || "",
|
||||||
|
gitea_username: res.data.gitea_username || "",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load profile:', error);
|
console.error('Failed to load profile:', error);
|
||||||
|
|
@ -288,6 +290,18 @@ export default function Account() {
|
||||||
className="cyber-input"
|
className="cyber-input"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="gitea" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
|
||||||
|
<GitBranch className="w-3 h-3" /> Gitea 用户名
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
id="gitea"
|
||||||
|
value={form.gitea_username}
|
||||||
|
onChange={(e) => setForm({ ...form, gitea_username: e.target.value })}
|
||||||
|
placeholder="your-gitea-username"
|
||||||
|
className="cyber-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ interface SplashScreenProps {
|
||||||
// Enhanced boot sequence messages with icons
|
// Enhanced boot sequence messages with icons
|
||||||
const BOOT_SEQUENCE = [
|
const BOOT_SEQUENCE = [
|
||||||
{ text: "[INIT] Loading DeepAudit Core...", delay: 0, type: 'init' },
|
{ text: "[INIT] Loading DeepAudit Core...", delay: 0, type: 'init' },
|
||||||
{ text: "[SCAN] AI Code Review Engine v3.0", delay: 200, type: 'scan' },
|
{ text: "[SCAN] AI Code Review Engine", delay: 200, type: 'scan' },
|
||||||
{ text: "[LOAD] Vulnerability Pattern Database", delay: 400, type: 'load' },
|
{ text: "[LOAD] Vulnerability Pattern Database", delay: 400, type: 'load' },
|
||||||
{ text: "[SYNC] Agent Orchestration Module", delay: 600, type: 'sync' },
|
{ text: "[SYNC] Agent Orchestration Module", delay: 600, type: 'sync' },
|
||||||
{ text: "[READY] System Online", delay: 800, type: 'ready' },
|
{ text: "[READY] System Online", delay: 800, type: 'ready' },
|
||||||
|
|
@ -234,10 +234,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
|
||||||
<AppLogo size="xl" subtitle="AI Code Review Bot" />
|
<AppLogo size="xl" subtitle="AI Code Review Bot" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Version tag */}
|
{/* Version tag removed */}
|
||||||
<div className="mt-2 text-[10px] font-mono text-primary/50 tracking-widest">
|
|
||||||
[ v3.0.0 // NEURAL_CORE ]
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Terminal window - adaptive styling */}
|
{/* Terminal window - adaptive styling */}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export interface Profile {
|
||||||
role: 'admin' | 'member';
|
role: 'admin' | 'member';
|
||||||
github_username?: string;
|
github_username?: string;
|
||||||
gitlab_username?: string;
|
gitlab_username?: string;
|
||||||
|
gitea_username?: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue