Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Implement upload/download of trace records #22

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,9 @@
[submodule "libs/codetracer-python-recorder"]
path = libs/codetracer-python-recorder
url = https://github.com/metacraft-labs/codetracer-python-recorder.git
[submodule "libs/nimcrypto"]
path = libs/nimcrypto
url = https://github.com/cheatfate/nimcrypto.git
[submodule "libs/zip"]
path = libs/zip
url = [email protected]:nim-lang/zip.git
1 change: 1 addition & 0 deletions libs/nimcrypto
Submodule nimcrypto added at 69eec0
1 change: 1 addition & 0 deletions libs/zip
Submodule zip added at 06f5b0
2 changes: 2 additions & 0 deletions nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ path:"libs/chronos"
path:"libs/parsetoml/src"
path:"libs/nim-result"
path:"libs/nim-confutils"
path:"libs/nimcrypto"
path:"libs/zip"

gcc.options.debug = "-O0 -g3"
3 changes: 2 additions & 1 deletion nix/shells/main.nix
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ in
unixtools.killall
# zip
# unzip
libzip
# curl

# for pgrep at least
Expand Down Expand Up @@ -150,7 +151,7 @@ in
# copied case for libstdc++.so (needed by better-sqlite3) from
# https://discourse.nixos.org/t/what-package-provides-libstdc-so-6/18707/4:
# gcc.cc.lib ..
export CT_LD_LIBRARY_PATH="${sqlite.out}/lib/:${pcre.out}/lib:${glib.out}/lib:${openssl.out}/lib:${gcc.cc.lib}/lib";
export CT_LD_LIBRARY_PATH="${sqlite.out}/lib/:${pcre.out}/lib:${glib.out}/lib:${openssl.out}/lib:${gcc.cc.lib}/lib:${libzip.out}/lib";

export RUST_LOG=info

Expand Down
5 changes: 3 additions & 2 deletions src/common/common_trace_index.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ const SQL_INITIAL_INSERT_STATEMENTS = @[

const SQL_ALTER_TABLE_STATEMENTS: seq[string] = @[
# example: adding a new column
"""ALTER TABLE traces ADD COLUMN calltraceMode text;""",
"""ALTER TABLE traces RENAME COLUMN callgraph TO calltrace"""
"""ALTER TABLE traces ADD COLUMN remoteShareDownloadId text;""",
"""ALTER TABLE traces ADD COLUMN remoteShareControlId text;""",
"""ALTER TABLE traces ADD COLUMN remoteShareExpireTime INTEGER DEFAULT -1;"""
# """ALTER TABLE traces ADD COLUMN love integer;"""
]
16 changes: 16 additions & 0 deletions src/common/common_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ type
rrPid*: int
exitCode*: int
calltraceMode*: CalltraceMode
downloadKey*: langstring
controlId*: langstring
onlineExpireTime*: int

CalltraceMode* {.pure.} = enum NoInstrumentation, CallKeyOnly, RawRecordNoValues, FullRecord

Expand Down Expand Up @@ -1341,6 +1344,19 @@ type
BugReportArg* = object ## BugReport arg
title*: langstring
description*: langstring

UploadTraceArg* = object
trace*: Trace
programName*: langstring

UploadedTraceData* = object
downloadKey*: langstring
controlId*: langstring
expireTime*: langstring

DeleteTraceArg* = object
traceId*: int
controlId*: langstring

DbEventKind* {.pure.} = enum Record, Trace, History

Expand Down
61 changes: 56 additions & 5 deletions src/common/trace_index.nim
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,47 @@ proc ensureDB(test: bool): DBConn =
globalDbMap[test.int] = db
db

proc updateField*(
id: int,
fieldName: string,
fieldValue: string,
test: bool
) =
let db = ensureDB(test)
db.exec(
sql(&"UPDATE traces SET {fieldName} = ? WHERE id = ?"),
fieldValue, id
)
db.close()

proc updateField*(
id: int,
fieldName: string,
fieldValue: int,
test: bool
) =
let db = ensureDB(test)
db.exec(
sql(&"UPDATE traces SET {fieldName} = ? WHERE id = ?"),
fieldValue, id
)
db.close()

proc getField*(
id: int,
fieldName: string,
test: bool
): string =
let db = ensureDB(test)
let res = db.getAllRows(
sql(&"SELECT {fieldName} FROM traces WHERE id = ? LIMIT 1"),
id
)
db.close()
if res.len > 0:
return res[0][0]
return ""

proc recordTrace*(
id: int,
program: string,
Expand All @@ -81,7 +122,8 @@ proc recordTrace*(
exitCode: int,
calltrace: bool,
calltraceMode: CalltraceMode,
test: bool): Trace =
test: bool,
downloadKey: string = ""): Trace =
# TODO pass here a Trace value and instead if neeeded construct it from other helpers

let currentDate: DateTime = now()
Expand All @@ -107,19 +149,19 @@ proc recordTrace*(
sourceFolders, lowLevelFolder, outputFolder,
lang, imported, shellID,
rrPid, exitCode,
calltrace, calltraceMode, date)
calltrace, calltraceMode, date, remoteShareDownloadId)
VALUES (?, ?, ?,
?, ?, ?, ?,
?, ?, ?,
?, ?, ?,
?, ?,
?, ?, ?)""",
?, ?, ?, ?)""",
$id, program, args.join(" "),
compileCommand, env, workdir, "", # <- output
sourceFolders, lowLevelFolder, outputFolder,
$(lang.int), $(imported.int), $shellID,
$rrPid, $exitCode,
ord(calltrace), $calltraceMode, $traceDate)
ord(calltrace), $calltraceMode, $traceDate, downloadKey)
break
except DbError:
echo "error: ", getCurrentExceptionMsg()
Expand Down Expand Up @@ -177,6 +219,12 @@ proc loadCalltraceMode*(raw: string, lang: Lang): CalltraceMode =
proc loadTrace(trace: Row, test: bool): Trace =
try:
let lang = trace[10].parseInt.Lang
var expireTime = -1
try:
expireTime = trace[20].parseInt
except:
discard

result = Trace(
id: trace[0].parseInt,
program: trace[1],
Expand All @@ -196,7 +244,10 @@ proc loadTrace(trace: Row, test: bool): Trace =
shellID: trace[14].parseInt,

calltrace: trace[15].parseInt != 0,
calltraceMode: loadCalltraceMode(trace[16], lang))
calltraceMode: loadCalltraceMode(trace[16], lang),
downloadKey: trace[18],
controlId: trace[19],
onlineExpireTime: expireTime)
except CatchableError as e:
# assume db schema change?
echo "internal error: ", e.msg
Expand Down
2 changes: 1 addition & 1 deletion src/config/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defaultBuild: ""
showMinimap: true

# for now local setup
webApiRoot: http://100.87.206.30:57103/api/codetracer
webApiRoot: http://localhost:55500/api/codetracer/anon

# # you can use KEY+OTHER
# # use PageUp, PageDown, CTRL, ALT, SHIFT
Expand Down
12 changes: 11 additions & 1 deletion src/ct/codetracerconf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type
install,
upload,
download,
cmdDelete,
# build,
record,
console,
Expand Down Expand Up @@ -264,7 +265,16 @@ type
of download:
traceRegistryId* {.
argument,
desc: "the trace registry unique id: <program-name>#<id> e.g. a.rb#5"
desc: "the trace registry unique id: <program-name>//<downloadId>//<password> e.g. noir//1234//asd"
.}: string
of cmdDelete:
traceId* {.
name: "trace-id"
desc: "trace trace unique id"
.}: int
controlId* {.
name: "control-id",
desc: "the trace control id to delete the online trace"
.}: string
of start_core:
coreTraceArg* {.
Expand Down
17 changes: 9 additions & 8 deletions src/ct/launch/launch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import
std/[strutils, strformat, osproc],
../../common/[ paths, types, intel_fix, install_utils, trace_index, start_utils ],
../utilities/[ git, env ],
../online_sharing/trace_manager,
../cli/[ logging, list, help ],
../trace/[ replay, record, run, metadata ],
../codetracerconf,
Expand Down Expand Up @@ -101,15 +102,15 @@ proc runInitial*(conf: CodetracerConf) =
notSupportedCommand($conf.cmd)
of StartupCommand.upload:
# similar to replay/console
notSupportedCommand($conf.cmd)
# eventually enable?
# uploadCommand(
# conf.uploadLastTraceMatchingPattern,
# conf.uploadTraceId,
# conf.uploadTraceFolder,
# replayInteractive)
uploadCommand(
conf.uploadLastTraceMatchingPattern,
conf.uploadTraceId,
conf.uploadTraceFolder,
replayInteractive)
of StartupCommand.download:
notSupportedCommand($conf.cmd)
downloadCommand(conf.traceRegistryId)
of StartupCommand.cmdDelete:
deleteTraceCommand(conf.traceId, conf.controlId)
# eventually enable?
# downloadCommand(conf.traceRegistryId)
# of StartupCommand.build:
Expand Down
68 changes: 68 additions & 0 deletions src/ct/online_sharing/security_upload.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import nimcrypto, zip/zipfiles, std/[ sequtils, strutils, strformat, os, osproc ]
import ../../common/[ config ]

proc generateSecurePassword*(): string =
var key: array[32, byte]
discard randomBytes(key)

result = key.mapIt(it.toHex(2)).join("")
return result

proc pkcs7Pad*(data: seq[byte], blockSize: int): seq[byte] =
let padLen = blockSize - (data.len mod blockSize)
result = data & repeat(cast[byte](padLen), padLen)

proc pkcs7Unpad*(data: seq[byte]): seq[byte] =
if data.len == 0:
raise newException(ValueError, "Data is empty, cannot unpad")

let padLen = int64(data[^1]) # Convert last byte to int64 safely
if padLen <= 0 or padLen > data.len:
raise newException(ValueError, "Invalid padding")

result = data[0 ..< data.len - padLen]

func toBytes*(s: string): seq[byte] =
## Convert a string to the corresponding byte sequence - since strings in
## nim essentially are byte sequences without any particular encoding, this
## simply copies the bytes without a null terminator
when nimvm:
var r = newSeq[byte](s.len)
for i, c in s:
r[i] = cast[byte](c)
r
else:
@(s.toOpenArrayByte(0, s.high))

proc encryptZip(zipFile, password: string) =
var iv: seq[byte] = password.toBytes()[0..15]

var aes: CBC[aes256]
aes.init(password.toOpenArrayByte(0, len(password) - 1), iv)

var zipData = readFile(zipFile).toBytes()
var paddedData = pkcs7Pad(zipData, 16)
var encrypted = newSeq[byte](paddedData.len)

aes.encrypt(paddedData, encrypted.toOpenArray(0, len(encrypted) - 1))
writeFile(zipFile & ".enc", encrypted)

proc zipFileWithEncryption*(inputFile: string, outputZip: string, password: string) =
var zip: ZipArchive
if not zip.open(outputZip, fmWrite):
raise newException(IOError, "Failed to create zip file: " & outputZip)

for file in walkDirRec(inputFile):
let relPath = file.relativePath(inputFile)
zip.addFile(relPath, file)

zip.close()
encryptZip(outputZip, password)
removeFile(outputZip)

proc uploadEncyptedZip*(file: string): (string, int) =
# TODO: Plug in http client instead of curl
let config = loadConfig(folder=getCurrentDir(), inTest=false)
let cmd = &"curl -s -X POST -F \"file=@{file}.enc\" {config.webApiRoot}/upload"
let (output, exitCode) = execCmdEx(cmd)
(output, exitCode)
Loading