stuff
This commit is contained in:
parent
341a78774f
commit
83b776c00e
9 changed files with 156 additions and 17 deletions
|
|
@ -54,11 +54,12 @@ class PackDtoConverter {
|
||||||
tip: available
|
tip: available
|
||||||
? null
|
? null
|
||||||
: canOpenForAdVal
|
: canOpenForAdVal
|
||||||
? TextPackTip(
|
? AssetPackTip(
|
||||||
'📺',
|
'asset:icons/ad.webp',
|
||||||
position: PackTipPosition.bottomRight,
|
position: PackTipPosition.bottomRight,
|
||||||
)
|
)
|
||||||
: TextPackTip('🔒'),
|
: AssetPackTip('asset:icons/lock.webp',
|
||||||
|
position: PackTipPosition.bottomRight,),
|
||||||
version: model.version,
|
version: model.version,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,44 @@ server {
|
||||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" 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
|
# Special rate limiting for login attempts
|
||||||
location /login {
|
location /login {
|
||||||
# Strict rate limiting for login
|
# Strict rate limiting for login
|
||||||
|
|
@ -62,9 +100,10 @@ server {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Proxy to code-server running on port 8443
|
# Proxy to code-server running on port 8443
|
||||||
|
# Increased rate limit for API and dynamic content
|
||||||
location / {
|
location / {
|
||||||
# Apply rate limiting
|
# Increased rate limiting (200 requests per minute with burst of 50)
|
||||||
limit_req zone=vscode_general burst=10 nodelay;
|
limit_req zone=vscode_general burst=50 nodelay;
|
||||||
limit_req_status 429;
|
limit_req_status 429;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:8443;
|
proxy_pass http://127.0.0.1:8443;
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ class _AppInitializerState extends State<_AppInitializer> {
|
||||||
log('Auto-login successful, creating UserScope', name: 'App');
|
log('Auto-login successful, creating UserScope', name: 'App');
|
||||||
// Create UserScope only for authenticated users
|
// Create UserScope only for authenticated users
|
||||||
widget.appScope.userScopeHolder.scope!.userStateManager.setUser(user);
|
widget.appScope.userScopeHolder.scope!.userStateManager.setUser(user);
|
||||||
|
// Notify router about auth change
|
||||||
|
widget.appScope.userScopeHolder.notifyAuthChanged();
|
||||||
log('UserScope created and user set', name: 'App');
|
log('UserScope created and user set', name: 'App');
|
||||||
} else {
|
} else {
|
||||||
log('No saved session, starting as guest without UserScope', name: 'App');
|
log('No saved session, starting as guest without UserScope', name: 'App');
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:yx_scope/yx_scope.dart';
|
import 'package:yx_scope/yx_scope.dart';
|
||||||
|
|
||||||
import 'user_scope.dart';
|
import 'user_scope.dart';
|
||||||
|
|
@ -8,11 +9,49 @@ import 'user_scope_container.dart';
|
||||||
/// Управляет жизненным циклом UserScope
|
/// Управляет жизненным циклом UserScope
|
||||||
class UserScopeHolder extends BaseChildScopeHolder<UserScope,
|
class UserScopeHolder extends BaseChildScopeHolder<UserScope,
|
||||||
UserScopeContainer, UserScopeParent> {
|
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
|
@override
|
||||||
UserScopeContainer createContainer(UserScopeParent parent) {
|
UserScopeContainer createContainer(UserScopeParent parent) {
|
||||||
return UserScopeContainer(parent: 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,9 @@ class _AuthPageState extends State<AuthPage> {
|
||||||
// Notify that UserScope has changed
|
// Notify that UserScope has changed
|
||||||
appScope.notifyUserScopeChanged();
|
appScope.notifyUserScopeChanged();
|
||||||
|
|
||||||
|
// Notify router about auth change
|
||||||
|
appScope.userScopeHolder.notifyAuthChanged();
|
||||||
|
|
||||||
// Navigate to home
|
// Navigate to home
|
||||||
router.go('/home');
|
router.go('/home');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -156,6 +159,9 @@ class _AuthPageState extends State<AuthPage> {
|
||||||
// Notify that UserScope has changed
|
// Notify that UserScope has changed
|
||||||
appScope.notifyUserScopeChanged();
|
appScope.notifyUserScopeChanged();
|
||||||
|
|
||||||
|
// Notify router about auth change
|
||||||
|
appScope.userScopeHolder.notifyAuthChanged();
|
||||||
|
|
||||||
// Navigate to home
|
// Navigate to home
|
||||||
router.go('/home');
|
router.go('/home');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,24 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||||
|
|
||||||
if (!mounted) return;
|
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
|
// Notify that UserScope has changed
|
||||||
appScope.notifyUserScopeChanged();
|
appScope.notifyUserScopeChanged();
|
||||||
|
|
||||||
|
// Notify router about auth change
|
||||||
|
appScope.userScopeHolder.notifyAuthChanged();
|
||||||
|
|
||||||
log('User logged out successfully', name: 'ProfilePage');
|
log('User logged out successfully', name: 'ProfilePage');
|
||||||
|
|
||||||
|
// Navigate to auth page
|
||||||
|
final router = GoRouter.of(context);
|
||||||
|
router.go('/auth');
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
const SnackBar(content: Text('Logged out successfully')),
|
const SnackBar(content: Text('Logged out successfully')),
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,30 @@ GoRouter createAppRouter({
|
||||||
}) {
|
}) {
|
||||||
return GoRouter(
|
return GoRouter(
|
||||||
initialLocation: '/home',
|
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: [
|
routes: [
|
||||||
// Главный Shell с Bottom Navigation
|
// Главный Shell с Bottom Navigation
|
||||||
ShellRoute(
|
ShellRoute(
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,8 @@ dev_dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# assets:
|
assets:
|
||||||
# - assets/images/
|
- icons/
|
||||||
# - assets/icons/
|
|
||||||
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: Nunito
|
- family: Nunito
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,12 @@ Deployed proper nginx configuration for vscode.mnemo-cards.online:
|
||||||
Created the following scripts in `tools/deploy/`:
|
Created the following scripts in `tools/deploy/`:
|
||||||
|
|
||||||
1. **fix-vscode-server.sh** - Diagnoses and fixes code-server installation and configuration
|
1. **fix-vscode-server.sh** - Diagnoses and fixes code-server installation and configuration
|
||||||
2. **check-nginx.sh** - Checks nginx status and reloads configuration
|
2. **fix-vscode-rate-limit.sh** - Fixes 429 errors by updating rate limits in nginx.conf
|
||||||
3. **deploy-vscode-nginx.sh** - Deploys VSCode nginx configuration to server
|
3. **check-nginx.sh** - Checks nginx status and reloads configuration
|
||||||
4. **fix-nginx-duplicates.sh** - Removes duplicate nginx configurations
|
4. **deploy-vscode-nginx.sh** - Deploys VSCode nginx configuration to server
|
||||||
5. **test-vscode-from-server.sh** - Tests VSCode connectivity from server
|
5. **fix-nginx-duplicates.sh** - Removes duplicate nginx configurations
|
||||||
6. **test-vscode-final.sh** - Final tests of both URLs
|
6. **test-vscode-from-server.sh** - Tests VSCode connectivity from server
|
||||||
|
7. **test-vscode-final.sh** - Final tests of both URLs
|
||||||
|
|
||||||
## How to Use
|
## How to Use
|
||||||
|
|
||||||
|
|
@ -143,6 +144,13 @@ nginx -t # Test configuration
|
||||||
2. Check nginx error logs: `tail -f /var/log/nginx/error.log`
|
2. Check nginx error logs: `tail -f /var/log/nginx/error.log`
|
||||||
3. Verify proxy_pass uses 127.0.0.1:8443 (not localhost)
|
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
|
### SSL Certificate Issues
|
||||||
Certificates are managed by Let's Encrypt and stored at:
|
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)
|
- code-server runs as root user (WorkingDirectory=/root)
|
||||||
- Authentication is enabled with password
|
- Authentication is enabled with password
|
||||||
- WebSocket support is enabled for VSCode features
|
- 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)
|
- Automatic restart is configured (Restart=always)
|
||||||
- Service is enabled to start on boot (enabled via systemctl)
|
- 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
|
1. ✅ Fixed code-server service configuration
|
||||||
2. ✅ Deployed nginx configuration
|
2. ✅ Deployed nginx configuration
|
||||||
3. ✅ Fixed IPv6/IPv4 issue (localhost → 127.0.0.1)
|
3. ✅ Fixed IPv6/IPv4 issue (localhost → 127.0.0.1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue