diff --git a/api/chalicelib/core/authorizers.py b/api/chalicelib/core/authorizers.py index 2ec3fa01f..46ec9e25a 100644 --- a/api/chalicelib/core/authorizers.py +++ b/api/chalicelib/core/authorizers.py @@ -15,7 +15,7 @@ def jwt_authorizer(token): token[1], config("jwt_secret"), algorithms=config("jwt_algorithm"), - audience=[ f"front:{helper.get_stage_name()}"] + audience=[f"front:{helper.get_stage_name()}"] ) except jwt.ExpiredSignatureError: print("! JWT Expired signature") @@ -37,12 +37,16 @@ def jwt_context(context): } +def get_jwt_exp(iat): + return iat // 1000 + config("JWT_EXPIRATION", cast=int) + TimeUTC.get_utc_offset() // 1000 + + def generate_jwt(id, tenant_id, iat, aud): token = jwt.encode( payload={ "userId": id, "tenantId": tenant_id, - "exp": iat // 1000 + config("JWT_EXPIRATION", cast=int) + TimeUTC.get_utc_offset() // 1000, + "exp": get_jwt_exp(iat), "iss": config("JWT_ISSUER"), "iat": iat // 1000, "aud": aud diff --git a/api/chalicelib/core/users.py b/api/chalicelib/core/users.py index 94c9261ea..1d4d64c93 100644 --- a/api/chalicelib/core/users.py +++ b/api/chalicelib/core/users.py @@ -602,12 +602,12 @@ def auth_exists(user_id, tenant_id, jwt_iat, jwt_aud): ) r = cur.fetchone() return r is not None \ - and r.get("jwt_iat") is not None \ - and (abs(jwt_iat - TimeUTC.datetime_to_timestamp(r["jwt_iat"]) // 1000) <= 1 \ - or (jwt_aud.startswith("plugin") \ - and (r["changed_at"] is None \ - or jwt_iat >= (TimeUTC.datetime_to_timestamp(r["changed_at"]) // 1000))) - ) + and r.get("jwt_iat") is not None \ + and (abs(jwt_iat - TimeUTC.datetime_to_timestamp(r["jwt_iat"]) // 1000) <= 1 \ + or (jwt_aud.startswith("plugin") \ + and (r["changed_at"] is None \ + or jwt_iat >= (TimeUTC.datetime_to_timestamp(r["changed_at"]) // 1000))) + ) def change_jwt_iat(user_id): @@ -648,9 +648,9 @@ def authenticate(email, password, for_change_password=False): return True r = helper.dict_to_camel_case(r) jwt_iat = change_jwt_iat(r['userId']) + iat = TimeUTC.datetime_to_timestamp(jwt_iat) return { - "jwt": authorizers.generate_jwt(r['userId'], r['tenantId'], - TimeUTC.datetime_to_timestamp(jwt_iat), + "jwt": authorizers.generate_jwt(r['userId'], r['tenantId'], iat=iat, aud=f"front:{helper.get_stage_name()}"), "email": email, **r diff --git a/api/chalicelib/utils/helper.py b/api/chalicelib/utils/helper.py index 7639f1950..61663ed3c 100644 --- a/api/chalicelib/utils/helper.py +++ b/api/chalicelib/utils/helper.py @@ -3,6 +3,7 @@ import random import re import string from typing import Union +from urllib.parse import urlparse from decouple import config @@ -98,7 +99,7 @@ TRACK_TIME = True def allow_captcha(): return config("captcha_server", default=None) is not None and config("captcha_key", default=None) is not None \ - and len(config("captcha_server")) > 0 and len(config("captcha_key")) > 0 + and len(config("captcha_server")) > 0 and len(config("captcha_key")) > 0 def string_to_sql_like(value): @@ -304,3 +305,7 @@ def __time_value(row): def is_saml2_available(): return config("hastSAML2", default=False, cast=bool) + + +def get_domain(): + return urlparse(config("SITE_URL")).netloc diff --git a/api/routers/core.py b/api/routers/core.py index 7c9d06d93..4dc462ae7 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -2,6 +2,7 @@ from typing import Union from decouple import config from fastapi import Depends, Body, HTTPException +from fastapi.responses import JSONResponse from starlette import status import schemas @@ -40,13 +41,18 @@ def login(data: schemas.UserLoginSchema = Body(...)): status_code=status.HTTP_401_UNAUTHORIZED, detail=r["errors"][0] ) + r["smtp"] = helper.has_smtp() - return { + content = { 'jwt': r.pop('jwt'), 'data': { "user": r } } + response = JSONResponse(content=content) + response.set_cookie(key="jwt", value=content['jwt'], domain=helper.get_domain(), + expires=config("JWT_EXPIRATION", cast=int)) + return response @app.post('/{projectId}/sessions/search', tags=["sessions"]) @@ -68,8 +74,8 @@ def session_ids_search(projectId: int, data: schemas.FlatSessionsSearchPayloadSc @app.get('/{projectId}/events/search', tags=["events"]) def events_search(projectId: int, q: str, type: Union[schemas.FilterType, schemas.EventType, - schemas.PerformanceEventType, schemas.FetchFilterType, - schemas.GraphqlFilterType, str] = None, + schemas.PerformanceEventType, schemas.FetchFilterType, + schemas.GraphqlFilterType, str] = None, key: str = None, source: str = None, live: bool = False, context: schemas.CurrentContext = Depends(OR_context)): if len(q) == 0: @@ -973,6 +979,7 @@ def get_limits(context: schemas.CurrentContext = Depends(OR_context)): } } + @app.get('/integrations/msteams/channels', tags=["integrations"]) def get_msteams_channels(context: schemas.CurrentContext = Depends(OR_context)): return {"data": webhook.get_by_type(tenant_id=context.tenant_id, webhook_type=schemas.WebhookType.msteams)} diff --git a/ee/api/chalicelib/core/authorizers.py b/ee/api/chalicelib/core/authorizers.py index 363745f4b..21a6634bd 100644 --- a/ee/api/chalicelib/core/authorizers.py +++ b/ee/api/chalicelib/core/authorizers.py @@ -38,13 +38,16 @@ def jwt_context(context): } +def get_jwt_exp(iat): + return iat // 1000 + config("JWT_EXPIRATION", cast=int) + TimeUTC.get_utc_offset() // 1000 + + def generate_jwt(id, tenant_id, iat, aud, exp=None): token = jwt.encode( payload={ "userId": id, "tenantId": tenant_id, - "exp": exp + TimeUTC.get_utc_offset() // 1000 if exp is not None \ - else iat // 1000 + config("JWT_EXPIRATION", cast=int) + TimeUTC.get_utc_offset() // 1000, + "exp": exp + TimeUTC.get_utc_offset() // 1000 if exp is not None else get_jwt_exp(iat), "iss": config("JWT_ISSUER"), "iat": iat // 1000, "aud": aud diff --git a/ee/api/chalicelib/core/users.py b/ee/api/chalicelib/core/users.py index b55600da2..423b7621c 100644 --- a/ee/api/chalicelib/core/users.py +++ b/ee/api/chalicelib/core/users.py @@ -678,12 +678,12 @@ def auth_exists(user_id, tenant_id, jwt_iat, jwt_aud): ) r = cur.fetchone() return r is not None \ - and r.get("jwt_iat") is not None \ - and (abs(jwt_iat - TimeUTC.datetime_to_timestamp(r["jwt_iat"]) // 1000) <= 1 \ - or (jwt_aud.startswith("plugin") \ - and (r["changed_at"] is None \ - or jwt_iat >= (TimeUTC.datetime_to_timestamp(r["changed_at"]) // 1000))) - ) + and r.get("jwt_iat") is not None \ + and (abs(jwt_iat - TimeUTC.datetime_to_timestamp(r["jwt_iat"]) // 1000) <= 1 \ + or (jwt_aud.startswith("plugin") \ + and (r["changed_at"] is None \ + or jwt_iat >= (TimeUTC.datetime_to_timestamp(r["changed_at"]) // 1000))) + ) def change_jwt_iat(user_id): @@ -742,9 +742,9 @@ def authenticate(email, password, for_change_password=False): return True r = helper.dict_to_camel_case(r) jwt_iat = change_jwt_iat(r['userId']) + iat = TimeUTC.datetime_to_timestamp(jwt_iat) return { - "jwt": authorizers.generate_jwt(r['userId'], r['tenantId'], - TimeUTC.datetime_to_timestamp(jwt_iat), + "jwt": authorizers.generate_jwt(r['userId'], r['tenantId'], iat=iat, aud=f"front:{helper.get_stage_name()}"), "email": email, **r @@ -776,7 +776,7 @@ def authenticate_sso(email, internal_id, exp=None): r = helper.dict_to_camel_case(r) jwt_iat = TimeUTC.datetime_to_timestamp(change_jwt_iat(r['userId'])) return authorizers.generate_jwt(r['userId'], r['tenantId'], - jwt_iat, aud=f"front:{helper.get_stage_name()}", + iat=jwt_iat, aud=f"front:{helper.get_stage_name()}", exp=(exp + jwt_iat // 1000) if exp is not None else None) return None