locust-cloud 1.12.3__py3-none-any.whl → 1.13.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.
- locust_cloud/cloud.py +268 -133
- {locust_cloud-1.12.3.dist-info → locust_cloud-1.13.0.dist-info}/METADATA +3 -4
- locust_cloud-1.13.0.dist-info/RECORD +5 -0
- locust_cloud/__init__.py +0 -133
- locust_cloud/auth.py +0 -443
- locust_cloud/credential_manager.py +0 -141
- locust_cloud/idle_exit.py +0 -38
- locust_cloud/socket_logging.py +0 -127
- locust_cloud/timescale/exporter.py +0 -313
- locust_cloud/timescale/queries.py +0 -321
- locust_cloud/timescale/query.py +0 -74
- locust_cloud/webui/.gitignore +0 -4
- locust_cloud/webui/.prettierrc +0 -9
- locust_cloud/webui/dist/assets/index-D3YieuNV.js +0 -329
- locust_cloud/webui/dist/index.html +0 -20
- locust_cloud/webui/eslint.config.mjs +0 -83
- locust_cloud/webui/index.html +0 -20
- locust_cloud/webui/package.json +0 -52
- locust_cloud/webui/tsconfig.json +0 -27
- locust_cloud/webui/tsconfig.tsbuildinfo +0 -1
- locust_cloud/webui/vite.config.ts +0 -9
- locust_cloud/webui/vitest.config.ts +0 -16
- locust_cloud/webui/yarn.lock +0 -5816
- locust_cloud-1.12.3.dist-info/RECORD +0 -25
- {locust_cloud-1.12.3.dist-info → locust_cloud-1.13.0.dist-info}/WHEEL +0 -0
- {locust_cloud-1.12.3.dist-info → locust_cloud-1.13.0.dist-info}/entry_points.txt +0 -0
locust_cloud/__init__.py
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
import importlib.metadata
|
2
|
-
import os
|
3
|
-
import sys
|
4
|
-
|
5
|
-
os.environ["LOCUST_SKIP_MONKEY_PATCH"] = "1"
|
6
|
-
|
7
|
-
from locust_cloud.socket_logging import setup_socket_logging
|
8
|
-
|
9
|
-
if os.environ.get("LOCUST_MODE_MASTER") == "1":
|
10
|
-
major, minor, *rest = os.environ["LOCUSTCLOUD_CLIENT_VERSION"].split(".")
|
11
|
-
|
12
|
-
if int(major) > 1 or int(major) == 1 and int(minor) >= 12:
|
13
|
-
setup_socket_logging()
|
14
|
-
|
15
|
-
__version__ = importlib.metadata.version("locust-cloud")
|
16
|
-
|
17
|
-
import logging
|
18
|
-
|
19
|
-
import configargparse
|
20
|
-
import locust.env
|
21
|
-
import psycopg
|
22
|
-
from locust import events
|
23
|
-
from locust.argument_parser import LocustArgumentParser
|
24
|
-
from locust_cloud.auth import register_auth
|
25
|
-
from locust_cloud.idle_exit import IdleExit
|
26
|
-
from locust_cloud.timescale.exporter import Exporter
|
27
|
-
from locust_cloud.timescale.query import register_query
|
28
|
-
from psycopg.conninfo import make_conninfo
|
29
|
-
from psycopg_pool import ConnectionPool
|
30
|
-
|
31
|
-
logger = logging.getLogger(__name__)
|
32
|
-
|
33
|
-
|
34
|
-
@events.init_command_line_parser.add_listener
|
35
|
-
def add_arguments(parser: LocustArgumentParser):
|
36
|
-
if not (os.environ.get("PGHOST")):
|
37
|
-
parser.add_argument_group(
|
38
|
-
"locust-cloud",
|
39
|
-
"locust-cloud disabled, because PGHOST was not set - this is normal for local runs",
|
40
|
-
)
|
41
|
-
return
|
42
|
-
|
43
|
-
try:
|
44
|
-
REGION = os.environ["AWS_DEFAULT_REGION"]
|
45
|
-
except KeyError:
|
46
|
-
logger.fatal("Missing AWS_DEFAULT_REGION env var")
|
47
|
-
sys.exit(1)
|
48
|
-
|
49
|
-
os.environ["LOCUST_BUILD_PATH"] = os.path.join(os.path.dirname(__file__), "webui/dist")
|
50
|
-
locust_cloud = parser.add_argument_group(
|
51
|
-
"locust-cloud",
|
52
|
-
"Arguments for use with Locust cloud",
|
53
|
-
)
|
54
|
-
# do not set
|
55
|
-
# used for sending the run id from master to workers
|
56
|
-
locust_cloud.add_argument(
|
57
|
-
"--run-id",
|
58
|
-
type=str,
|
59
|
-
env_var="LOCUSTCLOUD_RUN_ID",
|
60
|
-
help=configargparse.SUPPRESS,
|
61
|
-
)
|
62
|
-
locust_cloud.add_argument(
|
63
|
-
"--allow-signup",
|
64
|
-
env_var="LOCUSTCLOUD_ALLOW_SIGNUP",
|
65
|
-
help=configargparse.SUPPRESS,
|
66
|
-
default=False,
|
67
|
-
action="store_true",
|
68
|
-
)
|
69
|
-
locust_cloud.add_argument(
|
70
|
-
"--allow-forgot-password",
|
71
|
-
env_var="LOCUSTCLOUD_FORGOT_PASSWORD",
|
72
|
-
help=configargparse.SUPPRESS,
|
73
|
-
default=False,
|
74
|
-
action="store_true",
|
75
|
-
)
|
76
|
-
locust_cloud.add_argument(
|
77
|
-
"--graph-viewer",
|
78
|
-
env_var="LOCUSTCLOUD_GRAPH_VIEWER",
|
79
|
-
help=configargparse.SUPPRESS,
|
80
|
-
default=False,
|
81
|
-
action="store_true",
|
82
|
-
)
|
83
|
-
locust_cloud.add_argument(
|
84
|
-
"--deployer-url",
|
85
|
-
type=str,
|
86
|
-
env_var="LOCUSTCLOUD_DEPLOYER_URL",
|
87
|
-
help=configargparse.SUPPRESS,
|
88
|
-
default=f"https://api.{REGION}.locust.cloud/1",
|
89
|
-
)
|
90
|
-
locust_cloud.add_argument(
|
91
|
-
"--profile",
|
92
|
-
type=str,
|
93
|
-
env_var="LOCUSTCLOUD_PROFILE",
|
94
|
-
help=configargparse.SUPPRESS,
|
95
|
-
default=None,
|
96
|
-
)
|
97
|
-
|
98
|
-
|
99
|
-
def set_autocommit(conn: psycopg.Connection):
|
100
|
-
conn.autocommit = True
|
101
|
-
|
102
|
-
|
103
|
-
@events.init.add_listener
|
104
|
-
def on_locust_init(environment: locust.env.Environment, **_args):
|
105
|
-
if not (os.environ.get("PGHOST")):
|
106
|
-
return
|
107
|
-
|
108
|
-
conninfo = make_conninfo(
|
109
|
-
sslmode="require",
|
110
|
-
)
|
111
|
-
pool = ConnectionPool(
|
112
|
-
conninfo,
|
113
|
-
min_size=1,
|
114
|
-
max_size=20,
|
115
|
-
configure=set_autocommit,
|
116
|
-
check=ConnectionPool.check_connection,
|
117
|
-
)
|
118
|
-
pool.wait(timeout=10)
|
119
|
-
|
120
|
-
if not environment.parsed_options.graph_viewer:
|
121
|
-
IdleExit(environment)
|
122
|
-
Exporter(environment, pool)
|
123
|
-
|
124
|
-
if environment.web_ui:
|
125
|
-
environment.web_ui.template_args["locustVersion"] = locust.__version__
|
126
|
-
environment.web_ui.template_args["locustCloudVersion"] = __version__
|
127
|
-
environment.web_ui.template_args["webBasePath"] = environment.parsed_options.web_base_path
|
128
|
-
|
129
|
-
if environment.parsed_options.graph_viewer:
|
130
|
-
environment.web_ui.template_args["isGraphViewer"] = True
|
131
|
-
|
132
|
-
register_auth(environment)
|
133
|
-
register_query(environment, pool)
|
locust_cloud/auth.py
DELETED
@@ -1,443 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import os
|
3
|
-
from datetime import UTC, datetime, timedelta
|
4
|
-
from typing import Any, TypedDict, cast
|
5
|
-
|
6
|
-
import locust.env
|
7
|
-
import requests
|
8
|
-
import werkzeug
|
9
|
-
from flask import Blueprint, redirect, request, session, url_for
|
10
|
-
from flask_login import UserMixin, login_required, login_user, logout_user
|
11
|
-
from locust.html import render_template_from
|
12
|
-
from locust_cloud import __version__
|
13
|
-
|
14
|
-
logger = logging.getLogger(__name__)
|
15
|
-
|
16
|
-
|
17
|
-
class Credentials(TypedDict):
|
18
|
-
user_sub_id: str
|
19
|
-
refresh_token: str
|
20
|
-
|
21
|
-
|
22
|
-
class AuthUser(UserMixin):
|
23
|
-
def __init__(self, user_sub_id: str):
|
24
|
-
self.user_sub_id = user_sub_id
|
25
|
-
|
26
|
-
def get_id(self):
|
27
|
-
return self.user_sub_id
|
28
|
-
|
29
|
-
|
30
|
-
def set_credentials(username: str, credentials: Credentials, response: werkzeug.wrappers.response.Response):
|
31
|
-
if not credentials.get("user_sub_id"):
|
32
|
-
return response
|
33
|
-
|
34
|
-
user_sub_id = credentials["user_sub_id"]
|
35
|
-
refresh_token = credentials["refresh_token"]
|
36
|
-
|
37
|
-
response.set_cookie("username", username, expires=datetime.now(tz=UTC) + timedelta(days=365))
|
38
|
-
response.set_cookie("user_token", refresh_token, expires=datetime.now(tz=UTC) + timedelta(days=365))
|
39
|
-
response.set_cookie("user_sub_id", user_sub_id, expires=datetime.now(tz=UTC) + timedelta(days=365))
|
40
|
-
|
41
|
-
return response
|
42
|
-
|
43
|
-
|
44
|
-
def register_auth(environment: locust.env.Environment):
|
45
|
-
environment.web_ui.app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "") + os.getenv("CUSTOMER_ID", "")
|
46
|
-
environment.web_ui.app.debug = False
|
47
|
-
|
48
|
-
web_base_path = environment.parsed_options.web_base_path
|
49
|
-
auth_blueprint = Blueprint("locust_cloud_auth", __name__, url_prefix=web_base_path)
|
50
|
-
|
51
|
-
def load_user(user_sub_id: str):
|
52
|
-
username = request.cookies.get("username")
|
53
|
-
refresh_token = request.cookies.get("user_token")
|
54
|
-
|
55
|
-
if refresh_token:
|
56
|
-
environment.web_ui.template_args["username"] = username
|
57
|
-
return AuthUser(user_sub_id)
|
58
|
-
|
59
|
-
return None
|
60
|
-
|
61
|
-
environment.web_ui.login_manager.user_loader(load_user)
|
62
|
-
environment.web_ui.auth_args = cast(
|
63
|
-
Any,
|
64
|
-
{
|
65
|
-
"username_password_callback": f"{web_base_path}/authenticate",
|
66
|
-
},
|
67
|
-
)
|
68
|
-
|
69
|
-
environment.web_ui.auth_args["auth_providers"] = []
|
70
|
-
if environment.parsed_options.allow_signup:
|
71
|
-
environment.web_ui.auth_args["auth_providers"].append(
|
72
|
-
{"label": "Sign Up", "callback_url": f"{web_base_path}/signup"}
|
73
|
-
)
|
74
|
-
if environment.parsed_options.allow_forgot_password:
|
75
|
-
environment.web_ui.auth_args["auth_providers"].append(
|
76
|
-
{"label": "Forgot Password?", "callback_url": f"{web_base_path}/forgot-password"}
|
77
|
-
)
|
78
|
-
|
79
|
-
@auth_blueprint.route("/authenticate", methods=["POST"])
|
80
|
-
def login_submit():
|
81
|
-
username = request.form.get("username", "")
|
82
|
-
password = request.form.get("password")
|
83
|
-
|
84
|
-
try:
|
85
|
-
auth_response = requests.post(
|
86
|
-
f"{environment.parsed_options.deployer_url}/auth/login",
|
87
|
-
json={"username": username, "password": password},
|
88
|
-
headers={"X-Client-Version": __version__},
|
89
|
-
)
|
90
|
-
|
91
|
-
auth_response.raise_for_status()
|
92
|
-
|
93
|
-
credentials = auth_response.json()
|
94
|
-
|
95
|
-
if credentials.get("challenge_session"):
|
96
|
-
session["challenge_session"] = credentials.get("challenge_session")
|
97
|
-
session["username"] = username
|
98
|
-
|
99
|
-
session["auth_error"] = ""
|
100
|
-
|
101
|
-
return redirect(url_for("locust_cloud_auth.password_reset"))
|
102
|
-
if os.getenv("CUSTOMER_ID", "") and credentials.get("customer_id") != os.getenv("CUSTOMER_ID", ""):
|
103
|
-
session["auth_error"] = "Invalid login for this deployment"
|
104
|
-
return redirect(url_for("locust.login"))
|
105
|
-
|
106
|
-
if not credentials.get("user_sub_id"):
|
107
|
-
session["auth_error"] = "Unknown error during authentication, check logs and/or contact support"
|
108
|
-
return redirect(url_for("locust.login"))
|
109
|
-
|
110
|
-
response = redirect(url_for("locust.index"))
|
111
|
-
response = set_credentials(username, credentials, response)
|
112
|
-
login_user(AuthUser(credentials["user_sub_id"]))
|
113
|
-
|
114
|
-
return response
|
115
|
-
except requests.exceptions.HTTPError as e:
|
116
|
-
if e.response.status_code == 401:
|
117
|
-
session["auth_error"] = "Invalid username or password"
|
118
|
-
else:
|
119
|
-
logger.error(f"Unknown response from auth: {e.response.status_code} {e.response.text}")
|
120
|
-
|
121
|
-
session["auth_error"] = "Unknown error during authentication, check logs and/or contact support"
|
122
|
-
|
123
|
-
return redirect(url_for("locust.login"))
|
124
|
-
|
125
|
-
@auth_blueprint.route("/signup")
|
126
|
-
def signup():
|
127
|
-
if not environment.parsed_options.allow_signup:
|
128
|
-
return redirect(url_for("locust.login"))
|
129
|
-
|
130
|
-
if session.get("username"):
|
131
|
-
sign_up_args = {
|
132
|
-
"custom_form": {
|
133
|
-
"inputs": [
|
134
|
-
{
|
135
|
-
"label": "Confirmation Code",
|
136
|
-
"name": "confirmation_code",
|
137
|
-
"is_required": True,
|
138
|
-
},
|
139
|
-
],
|
140
|
-
"callback_url": f"{web_base_path}/confirm-signup",
|
141
|
-
"submit_button_text": "Confirm Email",
|
142
|
-
},
|
143
|
-
}
|
144
|
-
else:
|
145
|
-
sign_up_args = {
|
146
|
-
"custom_form": {
|
147
|
-
"inputs": [
|
148
|
-
{
|
149
|
-
"label": "Username",
|
150
|
-
"name": "username",
|
151
|
-
"is_required": True,
|
152
|
-
"type": "email",
|
153
|
-
},
|
154
|
-
{
|
155
|
-
"label": "Full Name",
|
156
|
-
"name": "customer_name",
|
157
|
-
"is_required": True,
|
158
|
-
},
|
159
|
-
{
|
160
|
-
"label": "Password",
|
161
|
-
"name": "password",
|
162
|
-
"is_secret": True,
|
163
|
-
"is_required": True,
|
164
|
-
},
|
165
|
-
{
|
166
|
-
"label": "Access Code",
|
167
|
-
"name": "access_code",
|
168
|
-
"is_required": True,
|
169
|
-
},
|
170
|
-
{
|
171
|
-
"label": "I consent to:\n\n1. Only test your own website/service or our example target\n\n2. Only use locust-cloud for its intended purpose: to load test other sites/services.\n\n3. Not attempt to circumvent your account limitations (e.g. max user count or max request count)\n\n4. Not use personal data (real names, addresses etc) in your tests.",
|
172
|
-
"name": "consent",
|
173
|
-
"default_value": False,
|
174
|
-
"is_required": True,
|
175
|
-
},
|
176
|
-
],
|
177
|
-
"callback_url": f"{web_base_path}/create-account",
|
178
|
-
"submit_button_text": "Sign Up",
|
179
|
-
},
|
180
|
-
}
|
181
|
-
|
182
|
-
if session.get("auth_info"):
|
183
|
-
sign_up_args["info"] = session["auth_info"]
|
184
|
-
if session.get("auth_sign_up_error"):
|
185
|
-
sign_up_args["error"] = session["auth_sign_up_error"]
|
186
|
-
|
187
|
-
return render_template_from(
|
188
|
-
"auth.html",
|
189
|
-
auth_args=sign_up_args,
|
190
|
-
)
|
191
|
-
|
192
|
-
@auth_blueprint.route("/create-account", methods=["POST"])
|
193
|
-
def create_account():
|
194
|
-
if not environment.parsed_options.allow_signup:
|
195
|
-
return redirect(url_for("locust.login"))
|
196
|
-
|
197
|
-
session["auth_sign_up_error"] = ""
|
198
|
-
session["auth_info"] = ""
|
199
|
-
|
200
|
-
username = request.form.get("username", "")
|
201
|
-
customer_name = request.form.get("customer_name", "")
|
202
|
-
password = request.form.get("password")
|
203
|
-
access_code = request.form.get("access_code")
|
204
|
-
|
205
|
-
try:
|
206
|
-
auth_response = requests.post(
|
207
|
-
f"{environment.parsed_options.deployer_url}/auth/signup",
|
208
|
-
json={"username": username, "password": password, "access_code": access_code},
|
209
|
-
)
|
210
|
-
|
211
|
-
auth_response.raise_for_status()
|
212
|
-
|
213
|
-
session["user_sub_id"] = auth_response.json().get("user_sub_id")
|
214
|
-
session["username"] = username
|
215
|
-
session["customer_name"] = customer_name
|
216
|
-
session["auth_info"] = (
|
217
|
-
"Please check your email and enter the confirmation code. If you didn't get a code after one minute, you can [request a new one](/resend-code)"
|
218
|
-
)
|
219
|
-
|
220
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
221
|
-
except requests.exceptions.HTTPError as e:
|
222
|
-
message = e.response.json().get("Message", "An unexpected error occured. Please try again.")
|
223
|
-
session["auth_info"] = ""
|
224
|
-
session["auth_sign_up_error"] = message
|
225
|
-
|
226
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
227
|
-
|
228
|
-
@auth_blueprint.route("/resend-code")
|
229
|
-
def resend_code():
|
230
|
-
if not session.get("username"):
|
231
|
-
session["auth_sign_up_error"] = "An unexpected error occured. Please try again."
|
232
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
233
|
-
|
234
|
-
try:
|
235
|
-
auth_response = requests.post(
|
236
|
-
f"{environment.parsed_options.deployer_url}/auth/resend-confirmation",
|
237
|
-
json={"username": session.get("username")},
|
238
|
-
)
|
239
|
-
|
240
|
-
auth_response.raise_for_status()
|
241
|
-
|
242
|
-
session["auth_sign_up_error"] = ""
|
243
|
-
session["auth_info"] = "Confirmation code sent, please check your email."
|
244
|
-
|
245
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
246
|
-
except requests.exceptions.HTTPError as e:
|
247
|
-
message = e.response.json().get("Message", "An unexpected error occured. Please try again.")
|
248
|
-
session["auth_info"] = ""
|
249
|
-
session["auth_sign_up_error"] = message
|
250
|
-
|
251
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
252
|
-
|
253
|
-
@auth_blueprint.route("/confirm-signup", methods=["POST"])
|
254
|
-
def confirm_signup():
|
255
|
-
if not environment.parsed_options.allow_signup:
|
256
|
-
return redirect(url_for("locust.login"))
|
257
|
-
if not session.get("user_sub_id"):
|
258
|
-
session["auth_sign_up_error"] = "An unexpected error occured. Please try again."
|
259
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
260
|
-
|
261
|
-
session["auth_sign_up_error"] = ""
|
262
|
-
confirmation_code = request.form.get("confirmation_code")
|
263
|
-
|
264
|
-
try:
|
265
|
-
auth_response = requests.post(
|
266
|
-
f"{environment.parsed_options.deployer_url}/auth/confirm-signup",
|
267
|
-
json={
|
268
|
-
"username": session.get("username"),
|
269
|
-
"customer_name": session.get("customer_name"),
|
270
|
-
"user_sub_id": session["user_sub_id"],
|
271
|
-
"confirmation_code": confirmation_code,
|
272
|
-
},
|
273
|
-
)
|
274
|
-
|
275
|
-
auth_response.raise_for_status()
|
276
|
-
|
277
|
-
session["username"] = None
|
278
|
-
session["auth_info"] = "Account created successfully!"
|
279
|
-
session["auth_sign_up_error"] = ""
|
280
|
-
|
281
|
-
return redirect("https://docs.locust.cloud/")
|
282
|
-
except requests.exceptions.HTTPError as e:
|
283
|
-
message = e.response.json().get("Message", "An unexpected error occured. Please try again.")
|
284
|
-
session["auth_info"] = ""
|
285
|
-
session["auth_sign_up_error"] = message
|
286
|
-
|
287
|
-
return redirect(url_for("locust_cloud_auth.signup"))
|
288
|
-
|
289
|
-
@auth_blueprint.route("/forgot-password")
|
290
|
-
def forgot_password():
|
291
|
-
if not environment.parsed_options.allow_forgot_password:
|
292
|
-
return redirect(url_for("locust.login"))
|
293
|
-
|
294
|
-
forgot_password_args = {
|
295
|
-
"custom_form": {
|
296
|
-
"inputs": [
|
297
|
-
{
|
298
|
-
"label": "Username",
|
299
|
-
"name": "username",
|
300
|
-
"is_required": True,
|
301
|
-
"type": "email",
|
302
|
-
},
|
303
|
-
],
|
304
|
-
"callback_url": f"{web_base_path}/send-forgot-password",
|
305
|
-
"submit_button_text": "Reset Password",
|
306
|
-
},
|
307
|
-
"info": "Enter your email and we will send a code to reset your password",
|
308
|
-
}
|
309
|
-
|
310
|
-
if session.get("auth_error"):
|
311
|
-
forgot_password_args["error"] = session["auth_error"]
|
312
|
-
|
313
|
-
return render_template_from("auth.html", auth_args=forgot_password_args)
|
314
|
-
|
315
|
-
@auth_blueprint.route("/send-forgot-password", methods=["POST"])
|
316
|
-
def send_forgot_password():
|
317
|
-
if not environment.parsed_options.allow_forgot_password:
|
318
|
-
return redirect(url_for("locust.login"))
|
319
|
-
|
320
|
-
try:
|
321
|
-
username = request.form.get("username", "")
|
322
|
-
|
323
|
-
auth_response = requests.post(
|
324
|
-
f"{environment.parsed_options.deployer_url}/auth/forgot-password",
|
325
|
-
json={"username": username},
|
326
|
-
)
|
327
|
-
|
328
|
-
auth_response.raise_for_status()
|
329
|
-
|
330
|
-
session["username"] = username
|
331
|
-
|
332
|
-
return redirect(url_for("locust_cloud_auth.password_reset"))
|
333
|
-
except requests.exceptions.HTTPError as e:
|
334
|
-
message = e.response.json().get("Message", "An unexpected error occured. Please try again.")
|
335
|
-
session["auth_info"] = ""
|
336
|
-
session["auth_error"] = message
|
337
|
-
|
338
|
-
return redirect(url_for("locust_cloud_auth.forgot_password"))
|
339
|
-
|
340
|
-
@auth_blueprint.route("/password-reset")
|
341
|
-
def password_reset():
|
342
|
-
if not environment.parsed_options.allow_forgot_password and not session.get("challenge_session"):
|
343
|
-
return redirect(url_for("locust.login"))
|
344
|
-
|
345
|
-
if session.get("challenge_session"):
|
346
|
-
reset_password_args = {
|
347
|
-
"custom_form": {
|
348
|
-
"inputs": [
|
349
|
-
{
|
350
|
-
"label": "New Password",
|
351
|
-
"name": "new_password",
|
352
|
-
"is_required": True,
|
353
|
-
"is_secret": True,
|
354
|
-
},
|
355
|
-
],
|
356
|
-
"callback_url": f"{web_base_path}/confirm-reset-password",
|
357
|
-
"submit_button_text": "Set Password",
|
358
|
-
},
|
359
|
-
"info": "You must set a new password",
|
360
|
-
}
|
361
|
-
else:
|
362
|
-
reset_password_args = {
|
363
|
-
"custom_form": {
|
364
|
-
"inputs": [
|
365
|
-
{
|
366
|
-
"label": "Confirmation Code",
|
367
|
-
"name": "confirmation_code",
|
368
|
-
"is_required": True,
|
369
|
-
},
|
370
|
-
{
|
371
|
-
"label": "New Password",
|
372
|
-
"name": "new_password",
|
373
|
-
"is_required": True,
|
374
|
-
"is_secret": True,
|
375
|
-
},
|
376
|
-
],
|
377
|
-
"callback_url": f"{web_base_path}/confirm-reset-password",
|
378
|
-
"submit_button_text": "Reset Password",
|
379
|
-
},
|
380
|
-
"info": "Enter your the confirmation code that was sent to your email",
|
381
|
-
}
|
382
|
-
|
383
|
-
if session.get("auth_error"):
|
384
|
-
reset_password_args["error"] = session["auth_error"]
|
385
|
-
|
386
|
-
return render_template_from("auth.html", auth_args=reset_password_args)
|
387
|
-
|
388
|
-
@auth_blueprint.route("/confirm-reset-password", methods=["POST"])
|
389
|
-
def confirm_reset_password():
|
390
|
-
if not environment.parsed_options.allow_forgot_password and not session.get("challenge_session"):
|
391
|
-
return redirect(url_for("locust.login"))
|
392
|
-
|
393
|
-
try:
|
394
|
-
username = session["username"]
|
395
|
-
confirmation_code = request.form.get("confirmation_code")
|
396
|
-
new_password = request.form.get("new_password")
|
397
|
-
|
398
|
-
auth_response = requests.post(
|
399
|
-
f"{environment.parsed_options.deployer_url}/auth/password-reset",
|
400
|
-
json={
|
401
|
-
"username": username,
|
402
|
-
"confirmation_code": confirmation_code,
|
403
|
-
"new_password": new_password,
|
404
|
-
"challenge_session": session.get("challenge_session"),
|
405
|
-
},
|
406
|
-
)
|
407
|
-
|
408
|
-
auth_response.raise_for_status()
|
409
|
-
|
410
|
-
session["username"] = ""
|
411
|
-
session["auth_error"] = ""
|
412
|
-
|
413
|
-
if session.get("challenge_session"):
|
414
|
-
session["challenge_session"] = ""
|
415
|
-
|
416
|
-
return redirect(url_for("locust_cloud_auth.password_reset_success"))
|
417
|
-
|
418
|
-
session["auth_info"] = "Password reset successfully! Please login"
|
419
|
-
|
420
|
-
return redirect(url_for("locust.login"))
|
421
|
-
except requests.exceptions.HTTPError as e:
|
422
|
-
message = e.response.json().get("Message", "An unexpected error occured. Please try again.")
|
423
|
-
session["auth_info"] = ""
|
424
|
-
session["auth_error"] = message
|
425
|
-
|
426
|
-
return redirect(url_for("locust_cloud_auth.password_reset"))
|
427
|
-
|
428
|
-
@auth_blueprint.route("/password-reset-success")
|
429
|
-
def password_reset_success():
|
430
|
-
return render_template_from(
|
431
|
-
"auth.html",
|
432
|
-
auth_args={
|
433
|
-
"info": "Password successfully set! Please review the [documentation](https://docs.locust.cloud/) and start your first testrun! If you have already ran some tests, you may also [login](/login)"
|
434
|
-
},
|
435
|
-
)
|
436
|
-
|
437
|
-
@auth_blueprint.route("/logout", methods=["POST"])
|
438
|
-
@login_required
|
439
|
-
def logout():
|
440
|
-
logout_user()
|
441
|
-
return redirect(url_for("locust.login"))
|
442
|
-
|
443
|
-
environment.web_ui.app.register_blueprint(auth_blueprint)
|