mindroot 8.8.0__py3-none-any.whl → 8.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mindroot might be problematic. Click here for more details.
- mindroot/coreplugins/admin/static/js/plugin-advanced-install.js +43 -20
- mindroot/coreplugins/google_auth/README.md +76 -0
- mindroot/coreplugins/google_auth/__init__.py +1 -0
- mindroot/coreplugins/google_auth/inject/login.jinja2 +69 -0
- mindroot/coreplugins/google_auth/mod.py +1 -0
- mindroot/coreplugins/google_auth/router.py +170 -0
- mindroot/coreplugins/jwt_auth/middleware.py +52 -5
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/METADATA +4 -1
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/RECORD +13 -8
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/WHEEL +0 -0
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/entry_points.txt +0 -0
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-8.8.0.dist-info → mindroot-8.9.0.dist-info}/top_level.txt +0 -0
|
@@ -112,8 +112,19 @@ export class PluginAdvancedInstall extends PluginBase {
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
// Extract repo name from URL
|
|
116
|
-
|
|
115
|
+
// Extract repo name from URL - handle various GitHub URL formats
|
|
116
|
+
let repoPath = githubUrl;
|
|
117
|
+
|
|
118
|
+
// Handle full GitHub URLs
|
|
119
|
+
if (githubUrl.includes('github.com/')) {
|
|
120
|
+
const match = githubUrl.match(/github\.com\/([^/]+\/[^/]+)/);
|
|
121
|
+
if (match) {
|
|
122
|
+
repoPath = match[1];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Extract just the repo name for display
|
|
127
|
+
const repoName = repoPath.split('/').pop();
|
|
117
128
|
|
|
118
129
|
try {
|
|
119
130
|
// Close the modal
|
|
@@ -122,27 +133,39 @@ export class PluginAdvancedInstall extends PluginBase {
|
|
|
122
133
|
// Open the installation dialog
|
|
123
134
|
this.installDialog.open(repoName || 'GitHub Plugin', 'GitHub');
|
|
124
135
|
|
|
125
|
-
//
|
|
126
|
-
|
|
136
|
+
// Connect to SSE endpoint for streaming GitHub installation
|
|
137
|
+
// Build URL with properly encoded parameters
|
|
138
|
+
const params = new URLSearchParams();
|
|
139
|
+
params.append('plugin', repoName || 'plugin');
|
|
140
|
+
params.append('source', 'github');
|
|
141
|
+
params.append('source_path', repoPath);
|
|
127
142
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
143
|
+
const eventSource = new EventSource(`/plugin-manager/stream-install-plugin?${params.toString()}`);
|
|
144
|
+
|
|
145
|
+
eventSource.addEventListener('message', (event) => {
|
|
146
|
+
this.installDialog.addOutput(event.data, 'info');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
eventSource.addEventListener('error', (event) => {
|
|
150
|
+
this.installDialog.addOutput(event.data, 'error');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
eventSource.addEventListener('warning', (event) => {
|
|
154
|
+
this.installDialog.addOutput(event.data, 'warning');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
eventSource.addEventListener('complete', (event) => {
|
|
158
|
+
this.installDialog.addOutput(event.data, 'success');
|
|
137
159
|
this.installDialog.setComplete(false);
|
|
138
|
-
|
|
139
|
-
//
|
|
140
|
-
this.dispatch('plugin-installed');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
160
|
+
eventSource.close();
|
|
161
|
+
// Dispatch event for parent components to refresh their lists
|
|
162
|
+
this.dispatch('plugin-installed', { plugin: { name: repoName, source: 'github' } });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
eventSource.onerror = () => {
|
|
166
|
+
eventSource.close();
|
|
144
167
|
this.installDialog.setComplete(true);
|
|
145
|
-
}
|
|
168
|
+
};
|
|
146
169
|
} catch (error) {
|
|
147
170
|
this.installDialog.addOutput(`Failed to install plugin from GitHub: ${error.message}`, 'error');
|
|
148
171
|
this.installDialog.setComplete(true);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Google OAuth Authentication Plugin
|
|
2
|
+
|
|
3
|
+
This plugin adds Google Sign-In functionality to MindRoot, allowing users to authenticate using their Google accounts.
|
|
4
|
+
|
|
5
|
+
## Setup Instructions
|
|
6
|
+
|
|
7
|
+
### 1. Create Google OAuth Credentials
|
|
8
|
+
|
|
9
|
+
1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
|
|
10
|
+
2. Create a new project or select an existing one
|
|
11
|
+
3. Enable the Google+ API for your project
|
|
12
|
+
4. Go to "Credentials" in the left sidebar
|
|
13
|
+
5. Click "Create Credentials" > "OAuth client ID"
|
|
14
|
+
6. Select "Web application" as the application type
|
|
15
|
+
7. Add your redirect URI (e.g., `http://localhost:8000/google_auth/callback` for local development)
|
|
16
|
+
8. Save your Client ID and Client Secret
|
|
17
|
+
|
|
18
|
+
### 2. Configure Environment Variables
|
|
19
|
+
|
|
20
|
+
Add the following to your `.env` file in the MindRoot root directory:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Google OAuth Configuration
|
|
24
|
+
GOOGLE_CLIENT_ID=your-client-id-here
|
|
25
|
+
GOOGLE_CLIENT_SECRET=your-client-secret-here
|
|
26
|
+
GOOGLE_REDIRECT_URI=http://localhost:8000/google_auth/callback
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For production, update `GOOGLE_REDIRECT_URI` to your actual domain:
|
|
30
|
+
```bash
|
|
31
|
+
GOOGLE_REDIRECT_URI=https://yourdomain.com/google_auth/callback
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Update Google OAuth Authorized Redirect URIs
|
|
35
|
+
|
|
36
|
+
Make sure to add your redirect URI to the authorized redirect URIs in your Google OAuth client settings.
|
|
37
|
+
|
|
38
|
+
## How It Works
|
|
39
|
+
|
|
40
|
+
1. Users click "Sign in with Google" on the login page
|
|
41
|
+
2. They are redirected to Google's OAuth consent screen
|
|
42
|
+
3. After authorization, Google redirects back to `/google_auth/callback`
|
|
43
|
+
4. The plugin:
|
|
44
|
+
- Verifies the OAuth response
|
|
45
|
+
- Creates a new user account if needed (username: `google_[partial_google_id]`)
|
|
46
|
+
- Sets the same JWT token used by the regular login system
|
|
47
|
+
- Redirects to the home page
|
|
48
|
+
|
|
49
|
+
## User Data
|
|
50
|
+
|
|
51
|
+
When a user signs in with Google:
|
|
52
|
+
- A new user account is created with a generated username
|
|
53
|
+
- Their Google email is stored
|
|
54
|
+
- Email is automatically verified if Google has verified it
|
|
55
|
+
- Additional Google profile info is stored in `google_info.json`
|
|
56
|
+
|
|
57
|
+
## Security Notes
|
|
58
|
+
|
|
59
|
+
- State tokens are used to prevent CSRF attacks
|
|
60
|
+
- Google ID tokens are verified server-side
|
|
61
|
+
- Users get the same JWT tokens as regular login
|
|
62
|
+
- Passwords for OAuth users are randomly generated and not used
|
|
63
|
+
|
|
64
|
+
## Troubleshooting
|
|
65
|
+
|
|
66
|
+
1. **"Google OAuth not configured" error**: Make sure you've set the environment variables
|
|
67
|
+
2. **Redirect URI mismatch**: Ensure the redirect URI in your `.env` matches exactly what's configured in Google Cloud Console
|
|
68
|
+
3. **Invalid state token**: This is a security feature - just try signing in again
|
|
69
|
+
|
|
70
|
+
## Integration with Existing System
|
|
71
|
+
|
|
72
|
+
The plugin integrates seamlessly with MindRoot's existing authentication:
|
|
73
|
+
- Uses the same JWT token system
|
|
74
|
+
- Compatible with existing middleware
|
|
75
|
+
- Users can access all the same features
|
|
76
|
+
- Admin can manage Google-authenticated users like any other users
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .mod import *
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{% block head_extra %}
|
|
2
|
+
<style>
|
|
3
|
+
.google-signin-btn {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding: 0.5rem;
|
|
9
|
+
margin-top: 1rem;
|
|
10
|
+
background-color: #4285f4;
|
|
11
|
+
color: white;
|
|
12
|
+
border: none;
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
font-size: 14px;
|
|
17
|
+
transition: background-color 0.3s;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.google-signin-btn:hover {
|
|
21
|
+
background-color: #357ae8;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.google-signin-btn svg {
|
|
25
|
+
width: 18px;
|
|
26
|
+
height: 18px;
|
|
27
|
+
margin-right: 8px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.divider {
|
|
31
|
+
text-align: center;
|
|
32
|
+
margin: 1rem 0;
|
|
33
|
+
position: relative;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.divider::before {
|
|
37
|
+
content: '';
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 50%;
|
|
40
|
+
left: 0;
|
|
41
|
+
right: 0;
|
|
42
|
+
height: 1px;
|
|
43
|
+
background-color: #555;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.divider span {
|
|
47
|
+
background-color: #2a2a2a;
|
|
48
|
+
padding: 0 10px;
|
|
49
|
+
position: relative;
|
|
50
|
+
color: #888;
|
|
51
|
+
font-size: 14px;
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
54
|
+
{% endblock %}
|
|
55
|
+
|
|
56
|
+
{% block content %}
|
|
57
|
+
<div class="divider">
|
|
58
|
+
<span>OR</span>
|
|
59
|
+
</div>
|
|
60
|
+
<a href="/google_auth/login" class="google-signin-btn">
|
|
61
|
+
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
62
|
+
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
|
|
63
|
+
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
|
|
64
|
+
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
|
|
65
|
+
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
|
|
66
|
+
</svg>
|
|
67
|
+
Sign in with Google
|
|
68
|
+
</a>
|
|
69
|
+
{% endblock %}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Google Auth plugin - provides Google OAuth2 authentication
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from fastapi import APIRouter, Request, HTTPException
|
|
2
|
+
from fastapi.responses import RedirectResponse, HTMLResponse
|
|
3
|
+
from lib.route_decorators import public_route
|
|
4
|
+
from lib.providers.services import service_manager
|
|
5
|
+
from mindroot.coreplugins.jwt_auth.middleware import create_access_token
|
|
6
|
+
from mindroot.coreplugins.user_service.models import UserCreate
|
|
7
|
+
from google.auth.transport import requests
|
|
8
|
+
from google.oauth2 import id_token
|
|
9
|
+
import google_auth_oauthlib.flow
|
|
10
|
+
import os
|
|
11
|
+
import secrets
|
|
12
|
+
import json
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
router = APIRouter()
|
|
16
|
+
|
|
17
|
+
# OAuth 2.0 configuration
|
|
18
|
+
CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID')
|
|
19
|
+
CLIENT_SECRET = os.environ.get('GOOGLE_CLIENT_SECRET')
|
|
20
|
+
REDIRECT_URI = os.environ.get('GOOGLE_REDIRECT_URI', 'http://localhost:8000/google_auth/callback')
|
|
21
|
+
|
|
22
|
+
# OAuth2 flow configuration
|
|
23
|
+
CLIENT_CONFIG = {
|
|
24
|
+
"web": {
|
|
25
|
+
"client_id": CLIENT_ID,
|
|
26
|
+
"client_secret": CLIENT_SECRET,
|
|
27
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
28
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
29
|
+
"redirect_uris": [REDIRECT_URI]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
SCOPES = ['openid', 'email', 'profile']
|
|
34
|
+
|
|
35
|
+
# Store state tokens temporarily (in production, use Redis or similar)
|
|
36
|
+
state_tokens = {}
|
|
37
|
+
|
|
38
|
+
@router.get("/google_auth/login")
|
|
39
|
+
@public_route()
|
|
40
|
+
async def google_login(request: Request):
|
|
41
|
+
"""Initiate Google OAuth2 login flow"""
|
|
42
|
+
if not CLIENT_ID or not CLIENT_SECRET:
|
|
43
|
+
raise HTTPException(status_code=500, detail="Google OAuth not configured")
|
|
44
|
+
|
|
45
|
+
# Create flow instance
|
|
46
|
+
flow = google_auth_oauthlib.flow.Flow.from_client_config(
|
|
47
|
+
CLIENT_CONFIG,
|
|
48
|
+
scopes=SCOPES
|
|
49
|
+
)
|
|
50
|
+
flow.redirect_uri = REDIRECT_URI
|
|
51
|
+
|
|
52
|
+
# Generate state token for CSRF protection
|
|
53
|
+
state = secrets.token_urlsafe(32)
|
|
54
|
+
authorization_url, _ = flow.authorization_url(
|
|
55
|
+
access_type='offline',
|
|
56
|
+
state=state,
|
|
57
|
+
prompt='select_account'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Store state token
|
|
61
|
+
state_tokens[state] = True
|
|
62
|
+
|
|
63
|
+
return RedirectResponse(url=authorization_url)
|
|
64
|
+
|
|
65
|
+
@router.get("/google_auth/callback")
|
|
66
|
+
@public_route()
|
|
67
|
+
async def google_callback(request: Request, code: str, state: str):
|
|
68
|
+
"""Handle Google OAuth2 callback"""
|
|
69
|
+
# Verify state token
|
|
70
|
+
if state not in state_tokens:
|
|
71
|
+
return RedirectResponse(url="/login?error=Invalid+state+token")
|
|
72
|
+
|
|
73
|
+
# Remove used state token
|
|
74
|
+
del state_tokens[state]
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Create flow instance
|
|
78
|
+
flow = google_auth_oauthlib.flow.Flow.from_client_config(
|
|
79
|
+
CLIENT_CONFIG,
|
|
80
|
+
scopes=SCOPES,
|
|
81
|
+
state=state
|
|
82
|
+
)
|
|
83
|
+
flow.redirect_uri = REDIRECT_URI
|
|
84
|
+
|
|
85
|
+
# Exchange authorization code for tokens
|
|
86
|
+
flow.fetch_token(code=code)
|
|
87
|
+
|
|
88
|
+
# Get user info from ID token
|
|
89
|
+
credentials = flow.credentials
|
|
90
|
+
request_session = requests.Request()
|
|
91
|
+
id_info = id_token.verify_oauth2_token(
|
|
92
|
+
credentials.id_token,
|
|
93
|
+
request_session,
|
|
94
|
+
CLIENT_ID
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Extract user information
|
|
98
|
+
google_id = id_info['sub']
|
|
99
|
+
email = id_info['email']
|
|
100
|
+
name = id_info.get('name', email.split('@')[0])
|
|
101
|
+
email_verified = id_info.get('email_verified', False)
|
|
102
|
+
|
|
103
|
+
# Create username from email or name
|
|
104
|
+
username = f"google_{google_id[:8]}"
|
|
105
|
+
|
|
106
|
+
# Check if user exists
|
|
107
|
+
existing_user = await service_manager.get_user_data(username)
|
|
108
|
+
|
|
109
|
+
if not existing_user:
|
|
110
|
+
# Create new user
|
|
111
|
+
user_data = UserCreate(
|
|
112
|
+
username=username,
|
|
113
|
+
email=email,
|
|
114
|
+
password=secrets.token_urlsafe(32) # Random password for OAuth users
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Create user with email already verified if Google verified it
|
|
118
|
+
await service_manager.create_user(
|
|
119
|
+
user_data,
|
|
120
|
+
roles=["user"],
|
|
121
|
+
skip_verification=email_verified
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Update user metadata with Google info
|
|
125
|
+
user_dir = os.path.join("data/users", username)
|
|
126
|
+
google_info = {
|
|
127
|
+
"google_id": google_id,
|
|
128
|
+
"name": name,
|
|
129
|
+
"picture": id_info.get('picture', ''),
|
|
130
|
+
"locale": id_info.get('locale', ''),
|
|
131
|
+
"auth_method": "google_oauth"
|
|
132
|
+
}
|
|
133
|
+
with open(os.path.join(user_dir, "google_info.json"), 'w') as f:
|
|
134
|
+
json.dump(google_info, f, indent=2)
|
|
135
|
+
|
|
136
|
+
# Create JWT token
|
|
137
|
+
user_data = await service_manager.get_user_data(username)
|
|
138
|
+
access_token = create_access_token(data={"sub": username, **user_data.dict()})
|
|
139
|
+
|
|
140
|
+
# Create response with redirect
|
|
141
|
+
response = RedirectResponse(url="/", status_code=303)
|
|
142
|
+
|
|
143
|
+
# Set cookie
|
|
144
|
+
response.set_cookie(
|
|
145
|
+
key="access_token",
|
|
146
|
+
value=access_token,
|
|
147
|
+
max_age=604800, # 1 week
|
|
148
|
+
httponly=True,
|
|
149
|
+
samesite="Lax"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return response
|
|
153
|
+
|
|
154
|
+
except Exception as e:
|
|
155
|
+
print(f"Google OAuth error: {e}")
|
|
156
|
+
import traceback
|
|
157
|
+
traceback.print_exc()
|
|
158
|
+
return RedirectResponse(
|
|
159
|
+
url="/login?error=Google+authentication+failed",
|
|
160
|
+
status_code=303
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
@router.get("/google_auth/config_check")
|
|
164
|
+
@public_route()
|
|
165
|
+
async def config_check():
|
|
166
|
+
"""Check if Google OAuth is configured"""
|
|
167
|
+
return {
|
|
168
|
+
"configured": bool(CLIENT_ID and CLIENT_SECRET),
|
|
169
|
+
"redirect_uri": REDIRECT_URI
|
|
170
|
+
}
|
|
@@ -9,11 +9,58 @@ from lib.providers.services import service_manager
|
|
|
9
9
|
import os
|
|
10
10
|
from lib.session_files import load_session_data
|
|
11
11
|
from lib.utils.debug import debug_box
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
import secrets
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
def get_or_create_jwt_secret():
|
|
16
|
+
secret_key = os.environ.get("JWT_SECRET_KEY", None)
|
|
17
|
+
|
|
18
|
+
if secret_key:
|
|
19
|
+
print("JWT_SECRET_KEY found in environment variables")
|
|
20
|
+
return secret_key
|
|
21
|
+
|
|
22
|
+
# Check if .env file exists and contains JWT_SECRET_KEY
|
|
23
|
+
env_path = Path.cwd() / ".env"
|
|
24
|
+
|
|
25
|
+
if env_path.exists():
|
|
26
|
+
with open(env_path, 'r') as f:
|
|
27
|
+
lines = f.readlines()
|
|
28
|
+
for line in lines:
|
|
29
|
+
if line.strip().startswith('JWT_SECRET_KEY='):
|
|
30
|
+
# Extract the key value
|
|
31
|
+
key_value = line.strip().split('=', 1)[1]
|
|
32
|
+
if key_value:
|
|
33
|
+
print(f"JWT_SECRET_KEY found in {env_path}")
|
|
34
|
+
# Also set it in environment for current session
|
|
35
|
+
os.environ['JWT_SECRET_KEY'] = key_value
|
|
36
|
+
return key_value
|
|
37
|
+
|
|
38
|
+
# If we get here, no key was found anywhere, so generate one
|
|
39
|
+
print("JWT_SECRET_KEY not found, generating new key...")
|
|
40
|
+
secret_key = secrets.token_urlsafe(32)
|
|
41
|
+
|
|
42
|
+
# Save to .env file
|
|
43
|
+
# Check if file exists and needs a newline before appending
|
|
44
|
+
needs_newline = False
|
|
45
|
+
if env_path.exists() and env_path.stat().st_size > 0:
|
|
46
|
+
with open(env_path, 'rb') as f:
|
|
47
|
+
f.seek(-1, 2) # Go to last byte
|
|
48
|
+
last_char = f.read(1)
|
|
49
|
+
needs_newline = last_char != b'\n'
|
|
50
|
+
|
|
51
|
+
with open(env_path, 'a') as f:
|
|
52
|
+
if needs_newline:
|
|
53
|
+
f.write('\n')
|
|
54
|
+
f.write(f"JWT_SECRET_KEY={secret_key}\n")
|
|
55
|
+
|
|
56
|
+
print(f"Generated new JWT_SECRET_KEY and saved to {env_path}")
|
|
57
|
+
os.environ['JWT_SECRET_KEY'] = secret_key
|
|
58
|
+
|
|
59
|
+
return secret_key
|
|
60
|
+
|
|
61
|
+
# Get or create the secret key
|
|
62
|
+
SECRET_KEY = get_or_create_jwt_secret()
|
|
63
|
+
print(f"JWT_SECRET_KEY loaded successfully")
|
|
17
64
|
|
|
18
65
|
ALGORITHM = "HS256"
|
|
19
66
|
ACCESS_TOKEN_EXPIRE_MINUTES = 10080 # 1 week
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mindroot
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.9.0
|
|
4
4
|
Summary: MindRoot AI Agent Framework
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
License-File: LICENSE
|
|
@@ -30,4 +30,7 @@ Requires-Dist: bcrypt
|
|
|
30
30
|
Requires-Dist: rich
|
|
31
31
|
Requires-Dist: colorama
|
|
32
32
|
Requires-Dist: python-dotenv
|
|
33
|
+
Requires-Dist: google-auth
|
|
34
|
+
Requires-Dist: google-auth-oauthlib
|
|
35
|
+
Requires-Dist: google-auth-httplib2
|
|
33
36
|
Dynamic: license-file
|
|
@@ -51,7 +51,7 @@ mindroot/coreplugins/admin/static/js/missing-commands.js,sha256=adNF9GWN981_KX7H
|
|
|
51
51
|
mindroot/coreplugins/admin/static/js/model-preferences.js,sha256=J0G7gcGACaPyslWJO42urf5wbZZsqO0LyPicAu-uV_Y,3365
|
|
52
52
|
mindroot/coreplugins/admin/static/js/notification.js,sha256=296rVCr6MNtzvzdzW3bGiMa231-BnWJtwZZ_sDWX-3c,5633
|
|
53
53
|
mindroot/coreplugins/admin/static/js/persona-editor.js,sha256=xO2jobJXwqGY7Uajj3vQxyERubsHZovIPF_8FHpvzFE,8604
|
|
54
|
-
mindroot/coreplugins/admin/static/js/plugin-advanced-install.js,sha256=
|
|
54
|
+
mindroot/coreplugins/admin/static/js/plugin-advanced-install.js,sha256=nrCpHlQTd9c_SRIqR0MNqsqgocUPL1K7_yfA99f-MlM,7679
|
|
55
55
|
mindroot/coreplugins/admin/static/js/plugin-base.js,sha256=KWp5DqueHtyTxYKbuHMoFpoFXrfMbIjzK4M1ulAR9m8,5095
|
|
56
56
|
mindroot/coreplugins/admin/static/js/plugin-index-browser.js,sha256=P-V4wqlYGxjr7oF2LiD5ti8Is3wtSsKPwpRgRJpT0VI,10028
|
|
57
57
|
mindroot/coreplugins/admin/static/js/plugin-install-dialog.js,sha256=ty_dZ9dZcpp9El1j3eY4Z6Wp8iZ5WNkf_lHSV-W1IhA,8216
|
|
@@ -923,6 +923,11 @@ mindroot/coreplugins/events/mod.py,sha256=MsSFjiLMLJZ7QhUPpVBWKiyDnCzryquRyr329N
|
|
|
923
923
|
mindroot/coreplugins/events/router.py,sha256=a-77306_fQPNHPXP5aYtbpfC0gbqMBNRu04aYOh75L4,3587
|
|
924
924
|
mindroot/coreplugins/events/backup/mod.py,sha256=9QeJpg6WKwxRdjiKVHD1froguTe86FS2-2wWm1B9xa8,1832
|
|
925
925
|
mindroot/coreplugins/events/backup/router_backup.py,sha256=ImU8xoxdSd45V1yOFVqdtDQ614V6CMsDZQ1gtJj0Mnk,254
|
|
926
|
+
mindroot/coreplugins/google_auth/README.md,sha256=9BTSYrU-k22RshkKDsszZwrB40xFu-1JUBi34QD52I8,2801
|
|
927
|
+
mindroot/coreplugins/google_auth/__init__.py,sha256=qw8b_7YoN67q1kEdXYXmQkXycF1NaYb3dMbjP-6FsUs,19
|
|
928
|
+
mindroot/coreplugins/google_auth/mod.py,sha256=wVhrOK7gw7kTjGRCS3nlhbELHPxydUqKMDQcjdGIUfU,61
|
|
929
|
+
mindroot/coreplugins/google_auth/router.py,sha256=15ix01TVTexfhgGRAhkNiQeHZamj-jqNDBNVQm1yqW4,5519
|
|
930
|
+
mindroot/coreplugins/google_auth/inject/login.jinja2,sha256=Vlihmk8vgxup0Y6Pvi5nzvbZUQyhUzZH0I5qREW_Vj8,1944
|
|
926
931
|
mindroot/coreplugins/home/mod.py,sha256=MsSFjiLMLJZ7QhUPpVBWKiyDnCzryquRyr329NoCACI,2
|
|
927
932
|
mindroot/coreplugins/home/router.py,sha256=kzPg2eIimG_2Qa1bZ0gKCmoo2uzd8GurrePODOO1How,1982
|
|
928
933
|
mindroot/coreplugins/home/static/css/dark.css,sha256=Q9FHaEsf9xeJjtouyKgr1Su6vTzsN07NHxxqDrDfyx8,14259
|
|
@@ -1694,7 +1699,7 @@ mindroot/coreplugins/index/static/js/lit-html/node/directives/until.js.map,sha25
|
|
|
1694
1699
|
mindroot/coreplugins/index/static/js/lit-html/node/directives/when.js,sha256=NLe0NJ-6jqjVDUrT_DzmSpREsRaLo1yarzdYcV_5xHY,181
|
|
1695
1700
|
mindroot/coreplugins/index/static/js/lit-html/node/directives/when.js.map,sha256=tOonih_-EaqrunhNGshA9xN--WIVdGikjg8MkVp0itQ,1534
|
|
1696
1701
|
mindroot/coreplugins/jwt_auth/__init__.py,sha256=qFCBnx0oAKTtMSXiPEa7VXOIlWDTU-5CY0XvodgSUlM,79
|
|
1697
|
-
mindroot/coreplugins/jwt_auth/middleware.py,sha256=
|
|
1702
|
+
mindroot/coreplugins/jwt_auth/middleware.py,sha256=Is8haTLe9K4PdN8hrpoN9lqee6fYfI8Viww6oZfTNIk,9227
|
|
1698
1703
|
mindroot/coreplugins/jwt_auth/mod.py,sha256=AfRDh9vyGGTE0qLdEOXl2TZYufYxqjsE34uIDQXq--o,1039
|
|
1699
1704
|
mindroot/coreplugins/jwt_auth/role_checks.py,sha256=bruZIIBSOvXNWB1YZ2s5btrbbXNf18w6MdORpJByV60,1555
|
|
1700
1705
|
mindroot/coreplugins/jwt_auth/router.py,sha256=ecXYao_UG33UjQF15Hi-tf_X0eFsqLEldyqGpt7JNSw,1162
|
|
@@ -1820,9 +1825,9 @@ mindroot/protocols/services/stream_chat.py,sha256=fMnPfwaB5fdNMBLTEg8BXKAGvrELKH
|
|
|
1820
1825
|
mindroot/registry/__init__.py,sha256=40Xy9bmPHsgdIrOzbtBGzf4XMqXVi9P8oZTJhn0r654,151
|
|
1821
1826
|
mindroot/registry/component_manager.py,sha256=WZFNPg4SNvpqsM5NFiC2DpgmrJQCyR9cNhrCBpp30Qk,995
|
|
1822
1827
|
mindroot/registry/data_access.py,sha256=NgNMamxIjaKeYxzxnVaQz1Y-Rm0AI51si3788_JHUTM,5316
|
|
1823
|
-
mindroot-8.
|
|
1824
|
-
mindroot-8.
|
|
1825
|
-
mindroot-8.
|
|
1826
|
-
mindroot-8.
|
|
1827
|
-
mindroot-8.
|
|
1828
|
-
mindroot-8.
|
|
1828
|
+
mindroot-8.9.0.dist-info/licenses/LICENSE,sha256=8plAmZh8y9ccuuqFFz4kp7G-cO_qsPgAOoHNvabSB4U,1070
|
|
1829
|
+
mindroot-8.9.0.dist-info/METADATA,sha256=43N17ZsLw9k6hQbsQHP21DJdu41cxnlVT7cc5KXlPRg,891
|
|
1830
|
+
mindroot-8.9.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
1831
|
+
mindroot-8.9.0.dist-info/entry_points.txt,sha256=0bpyjMccLttx6VcjDp6zfJPN0Kk0rffor6IdIbP0j4c,50
|
|
1832
|
+
mindroot-8.9.0.dist-info/top_level.txt,sha256=gwKm7DmNjhdrCJTYCrxa9Szne4lLpCtrEBltfsX-Mm8,9
|
|
1833
|
+
mindroot-8.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|