This commit is contained in:
Dmitry 2025-11-22 22:06:27 +03:00
parent 341a78774f
commit 83b776c00e
9 changed files with 156 additions and 17 deletions

View file

@ -54,11 +54,12 @@ class PackDtoConverter {
tip: available
? null
: canOpenForAdVal
? TextPackTip(
'📺',
? AssetPackTip(
'asset:icons/ad.webp',
position: PackTipPosition.bottomRight,
)
: TextPackTip('🔒'),
: AssetPackTip('asset:icons/lock.webp',
position: PackTipPosition.bottomRight,),
version: model.version,
);
}

View file

@ -34,6 +34,44 @@ server {
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Static files - no rate limiting (VSCode loads many files simultaneously)
location ~ ^/(static|out|node_modules|_next)/ {
# No rate limiting for static files
proxy_pass http://127.0.0.1:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Cache static files
proxy_cache_valid 200 1h;
add_header Cache-Control "public, max-age=3600";
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static file extensions - no rate limiting
location ~ \.(js|css|woff|woff2|ttf|eot|png|jpg|jpeg|gif|svg|ico|webp|map|json)$ {
# No rate limiting for static file extensions
proxy_pass http://127.0.0.1:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Cache static files
proxy_cache_valid 200 1h;
add_header Cache-Control "public, max-age=3600";
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Special rate limiting for login attempts
location /login {
# Strict rate limiting for login
@ -62,9 +100,10 @@ server {
}
# Proxy to code-server running on port 8443
# Increased rate limit for API and dynamic content
location / {
# Apply rate limiting
limit_req zone=vscode_general burst=10 nodelay;
# Increased rate limiting (200 requests per minute with burst of 50)
limit_req zone=vscode_general burst=50 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:8443;

View file

@ -94,6 +94,8 @@ class _AppInitializerState extends State<_AppInitializer> {
log('Auto-login successful, creating UserScope', name: 'App');
// Create UserScope only for authenticated users
widget.appScope.userScopeHolder.scope!.userStateManager.setUser(user);
// Notify router about auth change
widget.appScope.userScopeHolder.notifyAuthChanged();
log('UserScope created and user set', name: 'App');
} else {
log('No saved session, starting as guest without UserScope', name: 'App');

View file

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:yx_scope/yx_scope.dart';
import 'user_scope.dart';
@ -8,11 +9,49 @@ import 'user_scope_container.dart';
/// Управляет жизненным циклом UserScope
class UserScopeHolder extends BaseChildScopeHolder<UserScope,
UserScopeContainer, UserScopeParent> {
UserScopeHolder(super.parent);
UserScopeHolder(super.parent) : _authNotifier = ValueNotifier<bool>(false) {
// Подписываемся на изменения состояния scope
listen((scope) {
_updateAuthNotifier();
}, emitImmediately: true);
}
final ValueNotifier<bool> _authNotifier;
/// Notifier для отслеживания изменений состояния авторизации
///
/// Используется для обновления роутера при изменении авторизации
ValueNotifier<bool> get authNotifier => _authNotifier;
@override
UserScopeContainer createContainer(UserScopeParent parent) {
return UserScopeContainer(parent: parent);
}
void _updateAuthNotifier() {
final isAuth = isAuthenticated;
if (_authNotifier.value != isAuth) {
_authNotifier.value = isAuth;
}
}
/// Проверяет, авторизован ли пользователь
///
/// Возвращает true, если UserScope существует и пользователь авторизован
bool get isAuthenticated {
final userScope = scope;
if (userScope == null) {
return false;
}
return userScope.userStateManager.isAuthenticated;
}
/// Уведомляет о изменении состояния авторизации
///
/// Вызывается после изменения состояния пользователя (логин/логаут)
/// для немедленного обновления роутера
void notifyAuthChanged() {
_updateAuthNotifier();
}
}

View file

@ -72,6 +72,9 @@ class _AuthPageState extends State<AuthPage> {
// Notify that UserScope has changed
appScope.notifyUserScopeChanged();
// Notify router about auth change
appScope.userScopeHolder.notifyAuthChanged();
// Navigate to home
router.go('/home');
} else {
@ -156,6 +159,9 @@ class _AuthPageState extends State<AuthPage> {
// Notify that UserScope has changed
appScope.notifyUserScopeChanged();
// Notify router about auth change
appScope.userScopeHolder.notifyAuthChanged();
// Navigate to home
router.go('/home');
} else {

View file

@ -46,13 +46,24 @@ class _ProfilePageState extends State<ProfilePage> {
if (!mounted) return;
// UserScope will be automatically disposed when the holder is destroyed
// Update user state to guest
final userScope = appScope.userScopeHolder.scope;
if (userScope != null) {
userScope.userStateManager.logout();
}
// Notify that UserScope has changed
appScope.notifyUserScopeChanged();
// Notify router about auth change
appScope.userScopeHolder.notifyAuthChanged();
log('User logged out successfully', name: 'ProfilePage');
// Navigate to auth page
final router = GoRouter.of(context);
router.go('/auth');
// Show success message
messenger.showSnackBar(
const SnackBar(content: Text('Logged out successfully')),

View file

@ -20,6 +20,30 @@ GoRouter createAppRouter({
}) {
return GoRouter(
initialLocation: '/home',
refreshListenable: userScopeHolder.authNotifier,
redirect: (context, state) {
final isAuthenticated = userScopeHolder.isAuthenticated;
final location = state.uri.path;
// Если пользователь не авторизован
if (!isAuthenticated) {
// Разрешаем доступ только к странице авторизации
if (location == '/auth') {
return null; // Разрешить доступ
}
// Перенаправляем на страницу авторизации
return '/auth';
}
// Если пользователь авторизован и пытается зайти на /auth
if (location == '/auth') {
// Перенаправляем на главную страницу
return '/home';
}
// Разрешаем доступ к остальным страницам
return null;
},
routes: [
// Главный Shell с Bottom Navigation
ShellRoute(

View file

@ -102,9 +102,8 @@ dev_dependencies:
flutter:
uses-material-design: true
# assets:
# - assets/images/
# - assets/icons/
assets:
- icons/
fonts:
- family: Nunito

View file

@ -68,11 +68,12 @@ Deployed proper nginx configuration for vscode.mnemo-cards.online:
Created the following scripts in `tools/deploy/`:
1. **fix-vscode-server.sh** - Diagnoses and fixes code-server installation and configuration
2. **check-nginx.sh** - Checks nginx status and reloads configuration
3. **deploy-vscode-nginx.sh** - Deploys VSCode nginx configuration to server
4. **fix-nginx-duplicates.sh** - Removes duplicate nginx configurations
5. **test-vscode-from-server.sh** - Tests VSCode connectivity from server
6. **test-vscode-final.sh** - Final tests of both URLs
2. **fix-vscode-rate-limit.sh** - Fixes 429 errors by updating rate limits in nginx.conf
3. **check-nginx.sh** - Checks nginx status and reloads configuration
4. **deploy-vscode-nginx.sh** - Deploys VSCode nginx configuration to server
5. **fix-nginx-duplicates.sh** - Removes duplicate nginx configurations
6. **test-vscode-from-server.sh** - Tests VSCode connectivity from server
7. **test-vscode-final.sh** - Final tests of both URLs
## How to Use
@ -143,6 +144,13 @@ nginx -t # Test configuration
2. Check nginx error logs: `tail -f /var/log/nginx/error.log`
3. Verify proxy_pass uses 127.0.0.1:8443 (not localhost)
### 429 Too Many Requests
If you get `429 (Too Many Requests)` errors when loading VSCode:
1. Run the fix script: `./fix-vscode-rate-limit.sh`
2. Redeploy nginx config: `./deploy-vscode-nginx.sh`
3. The issue is usually caused by too strict rate limiting for static files
4. Static files are now excluded from rate limiting automatically
### SSL Certificate Issues
Certificates are managed by Let's Encrypt and stored at:
```
@ -173,12 +181,22 @@ code-server (127.0.0.1:8443) - VSCode Server
- code-server runs as root user (WorkingDirectory=/root)
- Authentication is enabled with password
- WebSocket support is enabled for VSCode features
- Rate limiting is configured to prevent abuse
- Rate limiting is configured to prevent abuse:
- General requests: 200 requests/minute (burst: 50)
- Login attempts: 5 requests/minute (burst: 2)
- Static files (JS, CSS, images): No rate limiting
- Automatic restart is configured (Restart=always)
- Service is enabled to start on boot (enabled via systemctl)
## Recent Changes (2025-11-19)
## Recent Changes
### 2025-11-22
1. ✅ Fixed 429 (Too Many Requests) error for static files
- Excluded static files (`/static/`, `/out/`, file extensions) from rate limiting
- Increased general rate limit from 30r/m to 200r/m
- Added caching for static files
### 2025-11-19
1. ✅ Fixed code-server service configuration
2. ✅ Deployed nginx configuration
3. ✅ Fixed IPv6/IPv4 issue (localhost → 127.0.0.1)