openreplay/api/chalicelib/core/sourcemaps.py
Kraiem Taha Yassine a29c02b43a
Api FastApi (#252)
* feat(api): dynamic-api 1/2

* feat(api): dynamic-api 2/2
feat(api): core-api 1/2

* feat(api): changed schemas
feat(api): aipkey authorizer
feat(api): jwt authorizer payload
feat(api): core-api 2/3

* feat(api): apikey authorizer
feat(api): shared context
feat(api): response editor
feat(api): middleware
feat(api): custom router
feat(api): fix auth double call

* feat(api): dashboard
feat(api): insights
feat(api): public api v1

* feat(api): allow full CORS

* feat(api): use decouple-config instead of env
feat(api): fixed conflict slack endpoint
feat(api): fixed favorite errors param

* feat(api): migration fixes

* feat(api): changes

* feat(api): crons

* feat(api): changes and fixes

* feat(api): added new endpoints
feat(api): applied new changes
feat(api): Docker image

* feat(api): EE 1/4

* feat(api): EE core_dynamic

* feat(api): global routers generator

* feat(api): project authorizer
feat(api): docker image
feat(api): crons

* feat(api): EE trace activity

* feat(api): changed ORRouter

* feat(api): EE trace activity parameters&payload

* feat(api): EE trace activity action name & path_format

* feat(db): user trace

* feat(api): EE trace activity ignore routes and hide attribute
feat(api): fix funnel payload schema

* feat(api): mobile support

* feat(api): changed build script

* feat(api): changed mobile sign endpoint
feat(api): changed requirements.txt

* feat(api): changed dockerfile

* feat(api): changed mobile-env-var

* feat(api): removed insights

* feat(api): changed EE Dockerfile

* feat(api): cast session_id to str for signing

* feat(api): fixed error_id type

* feat(api): fixed /errors priority conflict

* feat(api): fixed /errors/{errorId} default params

* feat(api): fixed change password after invitation

* feat(api): use background task for emails instead of low-timeout-api
feat(api): EE fixed missing required params

* feat(api): funnel-insights payload change

* feat(api): funnel-insights payload change

* feat(api): changed edit user payload schema

* feat(api): changed metrics payload schema

* feat(api): changed metrics payload schema

* feat(api): changed edit user default values
feat(api): fixed change error status route

* feat(api): changed edit user

* feat(api): stop user from changing his own role

* feat(api): changed add slack

* feat(api): changed get funnel

* feat(api): changed get funnel on the fly payload
feat(api): changed update payload

* feat(api): changed get funnel on the fly payload

* feat(api): changed update funnel payload

* feat(api): changed get funnel-sessions/issues on the fly payload

* feat(api): fixed funnel missing rangeValue

* feat(api): fixes

* feat(api): iceServers configuration

* feat(api): fix issueId casting

* feat(api): changed issues-sessions endpoint payload-schema

* feat(api): EE changed traces-ignored-routes

* feat(api): EE include core sessions.py

* feat(api): EE check licence on every request if expired

* feat(api): move general stats to dynamic

* feat(api): code cleanup
feat(api): removed sentry

* feat(api): changed traces-ignore-routes

* feat(api): changed dependencies

* feat(api): changed jwt-auth-response code

* feat(api): changed traces-ignore-routes

* feat(api): changed traces-ignore-routes

* feat(api): removed PyTZ
feat(api): migrated time-helper to zoneinfo

* feat(api): EE added missing dependency
feat(api): changed base docker image

* feat(api): merge after roles

* feat(api): EE roles fastapi

* feat(db): handel HTTPExceptions

* feat(db): changed payload schema

* feat(db): changed payload schema

* feat(api): included insights

* feat(api): removed unused helper

* feat(api): merge from dev to fatsapi

* feat(api): merge fixes
feat(api): SAML migration

* feat(api): changed GET /signup response
feat(api): changed EE Dockerfile

* feat(api): changed edition detection

* feat(api): include ee endpoints

* feat(api): add/edit member changes

* feat(api): saml changed redirect

* feat(api): track session's replay
feat(api): track error's details

* feat(api): ignore tracking for read roles

* feat(api): define global queue
feat(api): define global scheduler
feat(api): traces use queue
feat(api): traces batch insert
feat(DB): changed traces schema

* feat(api): fix signup captcha

* feat(api): fix signup captcha

* feat(api): optional roleId
feat(api): set roleId to member if None

* feat(api): fixed edit role

* feat(api): return role details when creating a new member

* feat(api): trace: use BackgroundTasks instead of BackgroundTask to not override previous tasks

* feat(api): trace: use BackgroundTask if no other background task is defined

* feat(api): optimised delete metadata

* feat(api): Notification optional message

* feat(api): fix background-task reference

* feat(api): fix trace-background-task

* feat(api): fixed g-captcha for reset password

* feat(api): fix edit self-user

* feat(api): fixed create github-issue

* feat(api): set misfire_grace_time for crons

* feat(api): removed chalice
feat(api): freeze dependencies

* feat(api): refactored blueprints

* feat(api): /metadata/session_search allow projectId=None

* feat(api): public API, changed userId type

* feat(api): fix upload sourcemaps

* feat(api): user-trace support ApiKey endpoints

* feat(api): fixed user-trace foreign key type

* feat(api): fixed trace schema

* feat(api): trace save auth-method

* feat(api): trace fixed auth-method

* feat(api): trace changed schema
2021-12-16 19:10:12 +01:00

162 lines
5.7 KiB
Python

from decouple import config
from chalicelib.utils import helper
from chalicelib.utils import s3
import hashlib
from urllib.parse import urlparse
from chalicelib.core import sourcemaps_parser
def __get_key(project_id, url):
u = urlparse(url)
new_url = u.scheme + "://" + u.netloc + u.path
return f"{project_id}/{hashlib.md5(new_url.encode()).hexdigest()}"
def presign_share_urls(project_id, urls):
results = []
for u in urls:
results.append(s3.get_presigned_url_for_sharing(bucket=config('sourcemaps_bucket'), expires_in=120,
key=__get_key(project_id, u),
check_exists=True))
return results
def presign_upload_urls(project_id, urls):
results = []
for u in urls:
results.append(s3.get_presigned_url_for_upload(bucket=config('sourcemaps_bucket'),
expires_in=1800,
key=__get_key(project_id, u)))
return results
def __format_frame_old(f):
if f.get("context") is None:
f["context"] = []
else:
f["context"] = [[f["line"], f["context"]]]
url = f.pop("url")
f["absPath"] = url
f["filename"] = urlparse(url).path
f["lineNo"] = f.pop("line")
f["colNo"] = f.pop("column")
f["function"] = f.pop("func")
return f
def __frame_is_valid(f):
return "columnNumber" in f and \
"lineNumber" in f and \
"fileName" in f
def __format_frame(f):
f["context"] = [] # no context by default
if "source" in f: f.pop("source")
url = f.pop("fileName")
f["absPath"] = url
f["filename"] = urlparse(url).path
f["lineNo"] = f.pop("lineNumber")
f["colNo"] = f.pop("columnNumber")
f["function"] = f.pop("functionName") if "functionName" in f else None
return f
def format_payload(p, truncate_to_first=False):
if type(p) is list:
return [__format_frame(f) for f in (p[:1] if truncate_to_first else p) if __frame_is_valid(f)]
if type(p) is dict:
stack = p.get("stack", [])
return [__format_frame_old(f) for f in (stack[:1] if truncate_to_first else stack)]
return []
def get_traces_group(project_id, payload):
frames = format_payload(payload)
results = [{}] * len(frames)
payloads = {}
all_exists = True
for i, u in enumerate(frames):
print("===============================")
print(u["absPath"])
print("converted to:")
key = __get_key(project_id, u["absPath"]) # use filename instead?
print(key)
print("===============================")
if key not in payloads:
file_exists = s3.exists(config('sourcemaps_bucket'), key)
all_exists = all_exists and file_exists
if not file_exists:
print(f"{u['absPath']} sourcemap (key '{key}') doesn't exist in S3")
payloads[key] = None
else:
payloads[key] = []
results[i] = dict(u)
results[i]["frame"] = dict(u)
if payloads[key] is not None:
payloads[key].append({"resultIndex": i,
"position": {"line": u["lineNo"], "column": u["colNo"]},
"frame": dict(u)})
for key in payloads.keys():
if payloads[key] is None:
continue
key_results = sourcemaps_parser.get_original_trace(key=key, positions=[o["position"] for o in payloads[key]])
for i, r in enumerate(key_results):
res_index = payloads[key][i]["resultIndex"]
# function name search by frontend lib is better than sourcemaps' one in most cases
if results[res_index].get("function") is not None:
r["function"] = results[res_index]["function"]
r["frame"] = payloads[key][i]["frame"]
results[res_index] = r
return fetch_missed_contexts(results), all_exists
def get_js_cache_path(fullURL):
p = urlparse(fullURL)
return p.scheme + '/' + p.netloc + p.path # TODO (Also in go assets library): What if URL with query? (like versions)
MAX_COLUMN_OFFSET = 60
def fetch_missed_contexts(frames):
source_cache = {}
for i in range(len(frames)):
if len(frames[i]["context"]) != 0:
continue
if frames[i]["frame"]["absPath"] in source_cache:
file = source_cache[frames[i]["frame"]["absPath"]]
else:
file = s3.get_file(config('js_cache_bucket'), get_js_cache_path(frames[i]["frame"]["absPath"]))
if file is None:
print(
f"File {get_js_cache_path(frames[i]['frame']['absPath'])} not found in {config('js_cache_bucket')}")
source_cache[frames[i]["frame"]["absPath"]] = file
if file is None:
continue
lines = file.split("\n")
if frames[i]["lineNo"] is None:
print("no original-source found for frame in sourcemap results")
frames[i] = frames[i]["frame"]
frames[i]["originalMapping"] = False
l = frames[i]["lineNo"] - 1 # starts from 1
c = frames[i]["colNo"] - 1 # starts from 1
if len(lines) == 1:
print(f"minified asset")
l = frames[i]["frame"]["lineNo"] - 1 # starts from 1
c = frames[i]["frame"]["colNo"] - 1 # starts from 1
elif l >= len(lines):
print(f"line number {l} greater than file length {len(lines)}")
continue
line = lines[l]
offset = c - MAX_COLUMN_OFFSET
if offset < 0: # if the line is shirt
offset = 0
frames[i]["context"].append([frames[i]["lineNo"], line[offset: c + MAX_COLUMN_OFFSET + 1]])
return frames