Updated to TOML v1.0.0.
This commit is contained in:
@@ -20,7 +20,6 @@ task client, "Build conquest client binary":
|
||||
|
||||
requires "nim >= 2.2.4"
|
||||
|
||||
requires "parsetoml >= 0.7.2"
|
||||
requires "nimcrypto >= 0.6.4"
|
||||
requires "tiny_sqlite >= 0.2.0"
|
||||
requires "winim >= 3.9.4"
|
||||
|
||||
@@ -29,10 +29,10 @@ endpoints = [
|
||||
# Metadata can be stored in a Header (e.g. JWT Token, Session Cookie), URI parameter or request body
|
||||
# Encoding is only applied to the payload and not the prepended or appended strings
|
||||
[http-get.agent.heartbeat]
|
||||
# placement = { type = "header", name = "Authorization" }
|
||||
# encoding = { type = "base64", url-safe = true }
|
||||
# prefix = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
|
||||
# suffix = ".######################################-####"
|
||||
placement = { type = "header", name = "Authorization" }
|
||||
encoding = { type = "base64", url-safe = true }
|
||||
prefix = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
|
||||
suffix = ".######################################-####"
|
||||
|
||||
# Example: PHP session cookie
|
||||
# placement = { type = "header", name = "Cookie" }
|
||||
@@ -45,8 +45,8 @@ endpoints = [
|
||||
# encoding = { type = "hex" }
|
||||
|
||||
# Example: Raw data in GET request body
|
||||
placement = { type = "body" }
|
||||
encoding = { type = "rot", key = 2 }
|
||||
# placement = { type = "body" }
|
||||
# encoding = { "none" }
|
||||
|
||||
# Defines arbitrary URI parameters that are added to the request
|
||||
[http-get.agent.parameters]
|
||||
|
||||
@@ -36,14 +36,14 @@ v = "###########"
|
||||
# Defines arbitrary headers that are added by the agent when performing a HTTP GET request
|
||||
[http-get.agent.headers]
|
||||
Host = "www.youtube.com"
|
||||
Sec-Ch-Ua = "'Not.A/Brand';v='99', 'Chromium';v='136'"
|
||||
Sec-Ch-Ua = "\"Not.A/Brand\";v=\"99\", \"Chromium\";v=\"136\""
|
||||
Sec-Ch-Ua-Mobile = "?0"
|
||||
Sec-Ch-Ua-Full-Version = "''"
|
||||
Sec-Ch-Ua-Arch = "''"
|
||||
Sec-Ch-Ua-Platform = "'Windows'"
|
||||
Sec-Ch-Ua-Platform-Version = "''"
|
||||
Sec-Ch-Ua-Model = "''"
|
||||
Sec-Ch-Ua-Bitness = "''"
|
||||
Sec-Ch-Ua-Full-Version = "\"\""
|
||||
Sec-Ch-Ua-Arch = "\"\""
|
||||
Sec-Ch-Ua-Platform = "\"Windows\""
|
||||
Sec-Ch-Ua-Platform-Version = "\"\""
|
||||
Sec-Ch-Ua-Model = "\"\""
|
||||
Sec-Ch-Ua-Bitness = "\"\""
|
||||
Sec-Ch-Ua-Wow64 = "?0"
|
||||
Accept-Language = [
|
||||
"en-US,en;q=0.9",
|
||||
@@ -58,7 +58,7 @@ Sec-Fetch-User = "?1"
|
||||
Sec-Fetch-Dest = "document"
|
||||
Priority = "u=0, i"
|
||||
|
||||
# Defines arbitrary headers that are added to the server's response
|
||||
# Defines arbitrary headers that are added to the server\"s response
|
||||
[http-get.server.headers]
|
||||
Content-Type = "text/html; charset=utf-8"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
@@ -67,19 +67,19 @@ Pragma = "no-cache"
|
||||
Expires = "Mon, 01 Jan 1990 00:00:00 GMT"
|
||||
Strict-Transport-Security = "max-age=31536000"
|
||||
X-Frame-Options = "SAMEORIGIN"
|
||||
Content-Security-Policy = "require-trusted-types-for 'script'"
|
||||
Content-Security-Policy = "require-trusted-types-for \"script\""
|
||||
Server = "ESF"
|
||||
X-Xss-Protection = "0"
|
||||
P3p = "CP='This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl=de for more info.'"
|
||||
Alt-Svc = "h3=':443'; ma=2592000,h3-29=':443'; ma=2592000"
|
||||
P3p = "CP=\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl=de for more info.\""
|
||||
Alt-Svc = "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"
|
||||
Set-Cookie = "__Secure-YEC=##############################################################################; Domain=.youtube.com; Expires=Mon, 07-Dec-2026 11:39:54 GMT; Path=/; Secure; HttpOnly; SameSite=lax"
|
||||
|
||||
# Defines how the server's response to the task retrieval request is rendered
|
||||
# Defines how the server"s response to the task retrieval request is rendered
|
||||
[http-get.server.output]
|
||||
placement = { type = "body" }
|
||||
encoding = { type = "base64" }
|
||||
prefix = "<!DOCTYPE html><html style='font-size: 10px;font-family: Roboto, Arial, sans-serif;' lang='de-DE'><head><script data-id='_gd' nonce='iqZzTrtVB86B0KRGblxg9Q'>window.WIZ_global_data = {'HiPsbb':0,'MUE6Ne':'youtube_web','MuJWjd':false};</script><meta http-equiv='origin-trial' content='"
|
||||
suffix = "'/><script nonce='iqZzTrtVB86B0KRGblxg9Q'>var ytcfg={d:function(){return window.yt&&yt.config_||ytcfg.data_||(ytcfg.data_={})},get:function(k,o){return k in ytcfg.d()?ytcfg.d()[k]:o},set:function(){var a=arguments;if(a.length>1)ytcfg.d()[a[0]]=a[1];else{var k;for(k in a[0])ytcfg.d()[k]=a[0][k]}}};window.ytcfg.set('EMERGENCY_BASE_URL', '/error_204?"
|
||||
prefix = "<!DOCTYPE html><html style=\"font-size: 10px;font-family: Roboto, Arial, sans-serif;\" lang=\"de-DE\"><head><script data-id=\"_gd\" nonce=\"iqZzTrtVB86B0KRGblxg9Q\">window.WIZ_global_data = {\"HiPsbb\":0,\"MUE6Ne\":\"youtube_web\",\"MuJWjd\":false};</script><meta http-equiv=\"origin-trial\" content=\""
|
||||
suffix = "\"/><script nonce=\"iqZzTrtVB86B0KRGblxg9Q\">var ytcfg={d:function(){return window.yt&&yt.config_||ytcfg.data_||(ytcfg.data_={})},get:function(k,o){return k in ytcfg.d()?ytcfg.d()[k]:o},set:function(){var a=arguments;if(a.length>1)ytcfg.d()[a[0]]=a[1];else{var k;for(k in a[0])ytcfg.d()[k]=a[0][k]}}};window.ytcfg.set(\"EMERGENCY_BASE_URL\", \"/error_204?"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# HTTP POST
|
||||
@@ -103,14 +103,14 @@ Referer = "https://www.youtube.com/watch?v=###########"
|
||||
Content-Type = "application/json"
|
||||
Connection = "Keep-Alive"
|
||||
Cache-Control = "no-cache"
|
||||
Sec-Ch-Ua = "'Not.A/Brand';v='99', 'Chromium';v='136'"
|
||||
Sec-Ch-Ua = "\"Not.A/Brand\";v=\"99\", \"Chromium\";v=\"136\""
|
||||
Sec-Ch-Ua-Mobile = "?0"
|
||||
Sec-Ch-Ua-Full-Version = "''"
|
||||
Sec-Ch-Ua-Arch = "''"
|
||||
Sec-Ch-Ua-Platform = "'Windows'"
|
||||
Sec-Ch-Ua-Platform-Version = "''"
|
||||
Sec-Ch-Ua-Model = "''"
|
||||
Sec-Ch-Ua-Bitness = "''"
|
||||
Sec-Ch-Ua-Full-Version = "\"\""
|
||||
Sec-Ch-Ua-Arch = "\"\""
|
||||
Sec-Ch-Ua-Platform = "\"Windows\""
|
||||
Sec-Ch-Ua-Platform-Version = "\"\""
|
||||
Sec-Ch-Ua-Model = "\"\""
|
||||
Sec-Ch-Ua-Bitness = "\"\""
|
||||
Sec-Ch-Ua-Wow64 = "?0"
|
||||
Cookie = "YSC=###########; SOCS=##############################################; VISITOR_PRIVACY_METADATA=##################################################################; __Secure-1PSIDTS=sidts-#######_##########################################_#########################; __Secure-3PSIDTS=sidts-#######_##########################################_#########################; HSID=####################;"
|
||||
|
||||
@@ -123,8 +123,8 @@ pretty-print = [
|
||||
[http-post.agent.output]
|
||||
placement = { type = "body" }
|
||||
encoding = { type = "base64", url-safe = true }
|
||||
prefix = "{'context':{'client':{'hl':'de','gl':'AT','remoteHost':'$$.1$$.$$.1$$','deviceMake':'','deviceModel':'','visitorData':'Cgt1M016MzRrZmhTUSj12MbIBjInCgJBVBIhEh0SGwsMDg8QERITFBUWFxgZGhscHR4fICEiIyQlJiBe','userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36,gzip(gfe)','clientName':'WEB','clientVersion':'2.20251107.01.00','osName':'Windows','osVersion':'10.0','originalUrl':'https://www.youtube.com/','screenPixelDensity':2,'platform':'DESKTOP','clientFormFactor':'UNKNOWN_FORM_FACTOR','configInfo':{'appInstallData':'"
|
||||
suffix = "'},'screenDensityFloat':1.5,'userInterfaceTheme':'USER_INTERFACE_THEME_DARK','timeZone':'Europe/Vienna','browserName':'Chrome','browserVersion':'142.0.0.0','acceptHeader':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7','deviceExperimentId':'ChxOelUzTVRBeU1qQTJPVEV4TkRFNU5qUXhOQT09EPXYxsgGGPXYxsgG','rolloutToken':'CJu4u9qz64jjcxCr8dad-t-QAxjzyIbunueQAw%3D%3D','screenWidthPoints':1920,'screenHeightPoints':1065,'utcOffsetMinutes':60,'connectionType':'CONN_CELLULAR_3G','memoryTotalKbytes':'8000000','mainAppWebInfo':{'graftUrl':'https://www.youtube.com/watch?v=###########&list=RD4WIMyqBG9gs&start_radio=1','pwaInstallabilityStatus':'PWA_INSTALLABILITY_STATUS_UNKNOWN','webDisplayMode':'WEB_DISPLAY_MODE_BROWSER','isWebNativeShareAvailable':true}},'user':{'lockedSafetyMode':false},'request':{'useSsl':true,'internalExperimentFlags':[],'consistencyTokenJars':[]},'clickTracking':{'clickTrackingParams':'CJgFEKVBIhMIucGi957nkAMVneRJBx3cFhscygEErMFOaw=='},'adSignalsInfo':{'params':[{'key':'dt','value':'1762765953510'},{'key':'flash','value':'0'},{'key':'frm','value':'0'},{'key':'u_tz','value':'60'},{'key':'u_his','value':'4'},{'key':'u_h','value':'1200'},{'key':'u_w','value':'1920'},{'key':'u_ah','value':'1152'},{'key':'u_aw','value':'1920'},{'key':'u_cd','value':'24'},{'key':'bc','value':'31'},{'key':'bih','value':'1065'},{'key':'biw','value':'1905'},{'key':'brdim','value':'0,0,0,0,1920,0,1920,1152,1920,1065'},{'key':'vis','value':'1'},{'key':'wgl','value':'true'},{'key':'ca_type','value':'image'}],'bid':'ANyPxKqp2RGW0TLEXMjNbBRm6ZPDYteE8iHnYK0DaJMOiTEHrbqefZtn6qfK_MhA2-ZgnoosEwKaN8pi77jJRptRzz5Rsm-P_w'}},'target':{'videoId':'###########'},'params':'Cg0KCzRXSU15cUJHOWdzIAAyDAiJ2cbIBhCm6ueLAQ%3D%3D'}"
|
||||
prefix = "{\"context\":{\"client\":{\"hl\":\"de\",\"gl\":\"AT\",\"remoteHost\":\"$$.1$$.$$.1$$\",\"deviceMake\":\"\",\"deviceModel\":\"\",\"visitorData\":\"Cgt1M016MzRrZmhTUSj12MbIBjInCgJBVBIhEh0SGwsMDg8QERITFBUWFxgZGhscHR4fICEiIyQlJiBe\",\"userAgent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36,gzip(gfe)\",\"clientName\":\"WEB\",\"clientVersion\":\"2.20251107.01.00\",\"osName\":\"Windows\",\"osVersion\":\"10.0\",\"originalUrl\":\"https://www.youtube.com/\",\"screenPixelDensity\":2,\"platform\":\"DESKTOP\",\"clientFormFactor\":\"UNKNOWN_FORM_FACTOR\",\"configInfo\":{\"appInstallData\":\""
|
||||
suffix = "\"},\"screenDensityFloat\":1.5,\"userInterfaceTheme\":\"USER_INTERFACE_THEME_DARK\",\"timeZone\":\"Europe/Vienna\",\"browserName\":\"Chrome\",\"browserVersion\":\"142.0.0.0\",\"acceptHeader\":\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\",\"deviceExperimentId\":\"ChxOelUzTVRBeU1qQTJPVEV4TkRFNU5qUXhOQT09EPXYxsgGGPXYxsgG\",\"rolloutToken\":\"CJu4u9qz64jjcxCr8dad-t-QAxjzyIbunueQAw%3D%3D\",\"screenWidthPoints\":1920,\"screenHeightPoints\":1065,\"utcOffsetMinutes\":60,\"connectionType\":\"CONN_CELLULAR_3G\",\"memoryTotalKbytes\":\"8000000\",\"mainAppWebInfo\":{\"graftUrl\":\"https://www.youtube.com/watch?v=###########&list=RD4WIMyqBG9gs&start_radio=1\",\"pwaInstallabilityStatus\":\"PWA_INSTALLABILITY_STATUS_UNKNOWN\",\"webDisplayMode\":\"WEB_DISPLAY_MODE_BROWSER\",\"isWebNativeShareAvailable\":true}},\"user\":{\"lockedSafetyMode\":false},\"request\":{\"useSsl\":true,\"internalExperimentFlags\":[],\"consistencyTokenJars\":[]},\"clickTracking\":{\"clickTrackingParams\":\"CJgFEKVBIhMIucGi957nkAMVneRJBx3cFhscygEErMFOaw==\"},\"adSignalsInfo\":{\"params\":[{\"key\":\"dt\",\"value\":\"1762765953510\"},{\"key\":\"flash\",\"value\":\"0\"},{\"key\":\"frm\",\"value\":\"0\"},{\"key\":\"u_tz\",\"value\":\"60\"},{\"key\":\"u_his\",\"value\":\"4\"},{\"key\":\"u_h\",\"value\":\"1200\"},{\"key\":\"u_w\",\"value\":\"1920\"},{\"key\":\"u_ah\",\"value\":\"1152\"},{\"key\":\"u_aw\",\"value\":\"1920\"},{\"key\":\"u_cd\",\"value\":\"24\"},{\"key\":\"bc\",\"value\":\"31\"},{\"key\":\"bih\",\"value\":\"1065\"},{\"key\":\"biw\",\"value\":\"1905\"},{\"key\":\"brdim\",\"value\":\"0,0,0,0,1920,0,1920,1152,1920,1065\"},{\"key\":\"vis\",\"value\":\"1\"},{\"key\":\"wgl\",\"value\":\"true\"},{\"key\":\"ca_type\",\"value\":\"image\"}],\"bid\":\"ANyPxKqp2RGW0TLEXMjNbBRm6ZPDYteE8iHnYK0DaJMOiTEHrbqefZtn6qfK_MhA2-ZgnoosEwKaN8pi77jJRptRzz5Rsm-P_w\"}},\"target\":{\"videoId\":\"###########\"},\"params\":\"Cg0KCzRXSU15cUJHOWdzIAAyDAiJ2cbIBhCm6ueLAQ%3D%3D\"}"
|
||||
|
||||
[http-post.server.headers]
|
||||
Content-Type = "application/json; charset=utf-8"
|
||||
@@ -135,7 +135,7 @@ Expires = "Mon, 01 Jan 1990 00:00:00 GMT"
|
||||
Server = "ESF"
|
||||
X-Xss-Protection = "0"
|
||||
Strict-Transport-Security = "max-age=31536000"
|
||||
Alt-Svc = "h3=':443'; ma=2592000,h3-29=':443'; ma=2592000"
|
||||
Alt-Svc = "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"
|
||||
|
||||
[http-post.server.output]
|
||||
body = "{'responseContext': {}}"
|
||||
body = "{\"responseContext\": {}}"
|
||||
@@ -1,6 +1,5 @@
|
||||
import parsetoml
|
||||
import ../utils/io
|
||||
import ../../common/[types, utils, crypto, serialize]
|
||||
import ../../common/[types, utils, crypto, profile, serialize]
|
||||
|
||||
const CONFIGURATION {.strdefine.}: string = ""
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import httpclient, strformat, strutils, asyncdispatch, base64, tables, parsetoml, random
|
||||
import httpclient, strformat, strutils, asyncdispatch, base64, tables, random
|
||||
import ../utils/io
|
||||
import ../../common/[types, utils, profile]
|
||||
|
||||
@@ -11,8 +11,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
|
||||
var body: string = ""
|
||||
|
||||
# Define request headers, as defined in profile
|
||||
for header, value in ctx.profile.getTable(protect("http-get.agent.headers")):
|
||||
client.headers.add(header, value.getStringValue())
|
||||
for header in ctx.profile.getTableKeys(protect("http-get.agent.headers")):
|
||||
client.headers.add(header.key, header.value.getStringValue())
|
||||
|
||||
# Select a random endpoint to make the request to
|
||||
var endpoint = ctx.profile.getString(protect("http-get.endpoints"))
|
||||
@@ -32,8 +32,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
|
||||
discard
|
||||
|
||||
# Define additional request parameters
|
||||
for param, value in ctx.profile.getTable(protect("http-get.agent.parameters")):
|
||||
endpoint &= fmt"{param}={value.getStringValue()}&"
|
||||
for param in ctx.profile.getTableKeys(protect("http-get.agent.parameters")):
|
||||
endpoint &= fmt"{param.key}={param.value.getStringValue()}&"
|
||||
|
||||
try:
|
||||
# Retrieve binary task data from listener and convert it to seq[bytes] for deserialization
|
||||
@@ -68,8 +68,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
|
||||
let client = newAsyncHttpClient(userAgent = ctx.profile.getString(protect("http-post.user-agent")))
|
||||
|
||||
# Define request headers, as defined in profile
|
||||
for header, value in ctx.profile.getTable(protect("http-post.agent.headers")):
|
||||
client.headers.add(header, value.getStringValue())
|
||||
for header in ctx.profile.getTableKeys(protect("http-post.agent.headers")):
|
||||
client.headers.add(header.key, header.value.getStringValue())
|
||||
|
||||
# Select a random endpoint to make the request to
|
||||
var endpoint = ctx.profile.getString(protect("http-post.endpoints"))
|
||||
@@ -95,8 +95,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
|
||||
discard
|
||||
|
||||
# Define additional request parameters
|
||||
for param, value in ctx.profile.getTable(protect("http-post.agent.parameters")):
|
||||
endpoint &= fmt"{param}={value.getStringValue()}&"
|
||||
for param in ctx.profile.getTableKeys(protect("http-post.agent.parameters")):
|
||||
endpoint &= fmt"{param.key}={param.value.getStringValue()}&"
|
||||
|
||||
try:
|
||||
# Send post request to team server
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,10 @@
|
||||
import whisky
|
||||
import tables, times, strutils, strformat, json, parsetoml, base64, native_dialogs
|
||||
import tables, times, strutils, strformat, json, base64, native_dialogs
|
||||
import ./utils/[appImGui, globals]
|
||||
import ./views/[dockspace, sessions, listeners, eventlog, console]
|
||||
import ./views/loot/[screenshots, downloads]
|
||||
import ./views/modals/generatePayload
|
||||
import ../common/[types, utils, crypto]
|
||||
import ../common/[types, utils, profile, crypto]
|
||||
import ./core/websocket
|
||||
|
||||
proc main(ip: string = "localhost", port: int = 37573) =
|
||||
@@ -85,7 +85,7 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
||||
wipeKey(clientKeyPair.privateKey)
|
||||
|
||||
of CLIENT_PROFILE:
|
||||
profile = parsetoml.parseString(event.data["profile"].getStr())
|
||||
profile = parseString(event.data["profile"].getStr())
|
||||
|
||||
of CLIENT_LISTENER_ADD:
|
||||
let listener = event.data.to(UIListener)
|
||||
|
||||
@@ -57,7 +57,7 @@ proc validateDecryption*(key: Key, iv: Iv, encData: seq[byte], sequenceNumber: u
|
||||
Elliptic curve cryptography ensures that the actual session key is never sent over the network
|
||||
Private keys and shared secrets are wiped from agent memory as soon as possible
|
||||
]#
|
||||
{.compile: "monocypher/monocypher.c".}
|
||||
{.compile: protect("monocypher/monocypher.c").}
|
||||
|
||||
# C function imports from (monocypher/monocypher.c)
|
||||
proc crypto_x25519*(shared_secret: ptr byte, your_secret_key: ptr byte, their_public_key: ptr byte) {.importc, cdecl.}
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
import parsetoml, strutils, sequtils, random, base64
|
||||
|
||||
import strutils, sequtils, random, base64
|
||||
import ./[types, utils]
|
||||
|
||||
proc findKey(profile: Profile, path: string): TomlValueRef =
|
||||
let keys = path.split(".")
|
||||
let target = keys[keys.high]
|
||||
|
||||
var current = profile
|
||||
for i in 0 ..< keys.high:
|
||||
let temp = current.getOrDefault(keys[i])
|
||||
if temp == nil:
|
||||
return nil
|
||||
current = temp
|
||||
|
||||
return current.getOrDefault(target)
|
||||
import ./toml/toml
|
||||
export parseFile, parseString, free, getTableKeys, getRandom
|
||||
|
||||
# Takes a specific "."-separated path as input and returns a default value if the key does not exits
|
||||
# Example: cq.profile.getString("http-get.agent.heartbeat.prefix", "not found") returns the string value of the
|
||||
# prefix key, or "not found" if the target key or any sub-tables don't exist
|
||||
# '#' characters represent wildcard characters and are replaced with a random alphanumerical character
|
||||
# '#' characters represent wildcard characters and are replaced with a random alphanumerical character (a-zA-Z0-9)
|
||||
# '$' characters are replaced with a random number (0-9)
|
||||
|
||||
#[
|
||||
Helper functions
|
||||
]#
|
||||
proc randomChar(): char =
|
||||
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
return alphabet[rand(alphabet.len - 1)]
|
||||
@@ -33,48 +25,53 @@ proc getRandom*(values: seq[TomlValueRef]): TomlValueRef =
|
||||
return nil
|
||||
return values[rand(values.len - 1)]
|
||||
|
||||
#[
|
||||
Wrapper functions
|
||||
]#
|
||||
proc getStringValue*(key: TomlValueRef, default: string = ""): string =
|
||||
# In some cases, the profile can define multiple values for a key, e.g. for HTTP headers
|
||||
# A random entry is selected from these specifications
|
||||
var value: string = ""
|
||||
if key.kind == TomlValueKind.String:
|
||||
value = key.getStr(default)
|
||||
elif key.kind == TomlValueKind.Array:
|
||||
value = key.getElems().getRandom().getStr(default)
|
||||
if key.isNil or key.kind == None:
|
||||
return default
|
||||
|
||||
# Replace '#' with a random alphanumerical character and return the resulting string
|
||||
var value: string = ""
|
||||
if key.kind == String:
|
||||
value = key.strVal
|
||||
elif key.kind == Array:
|
||||
let randomElem = getRandom(key.arrayVal)
|
||||
if randomElem != nil and randomElem.kind == String:
|
||||
value = randomElem.strVal
|
||||
|
||||
# Replace '#' with random alphanumerical character
|
||||
return value.mapIt(if it == '#': randomChar() elif it == '$': randomNumber() else: it).join("")
|
||||
|
||||
proc getString*(profile: Profile, path: string, default: string = ""): string =
|
||||
proc getString*(profile: Profile, path: string, default: string = ""): string =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getStringValue(default)
|
||||
|
||||
proc getBool*(profile: Profile, path: string, default: bool = false): bool =
|
||||
proc getInt*(profile: Profile, path: string, default: int = 0): int =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getBool(default)
|
||||
|
||||
proc getInt*(profile: Profile, path: string, default = 0): int =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getInt(default)
|
||||
|
||||
proc getTable*(profile: Profile, path: string): TomlTableRef =
|
||||
proc getBool*(profile: Profile, path: string, default: bool = false): bool =
|
||||
let key = profile.findKey(path)
|
||||
return key.getBool(default)
|
||||
|
||||
proc getTable*(profile: Profile, path: string): TomlTableRef =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return new TomlTableRef
|
||||
return key.getTable()
|
||||
|
||||
proc getArray*(profile: Profile, path: string): seq[TomlValueRef] =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
if key.kind != Array:
|
||||
return @[]
|
||||
return key.getElems()
|
||||
return key.getElems()
|
||||
|
||||
proc isArray*(profile: Profile, path: string): bool =
|
||||
let key = profile.findKey(path)
|
||||
return key.kind == Array
|
||||
|
||||
#[
|
||||
Data transformation
|
||||
]#
|
||||
proc applyDataTransformation*(profile: Profile, path: string, data: seq[byte]): string =
|
||||
# 1. Encoding
|
||||
var dataString: string
|
||||
|
||||
1983
src/common/toml/toml.c
Normal file
1983
src/common/toml/toml.c
Normal file
File diff suppressed because it is too large
Load Diff
137
src/common/toml/toml.h
Normal file
137
src/common/toml/toml.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef TOML_H
|
||||
#define TOML_H
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4996)
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
# define TOML_EXTERN extern "C"
|
||||
#else
|
||||
# define TOML_EXTERN extern
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct toml_table_t toml_table_t;
|
||||
typedef struct toml_array_t toml_array_t;
|
||||
typedef struct toml_value_t toml_value_t;
|
||||
typedef struct toml_timestamp_t toml_timestamp_t;
|
||||
typedef struct toml_keyval_t toml_keyval_t;
|
||||
typedef struct toml_arritem_t toml_arritem_t;
|
||||
typedef struct toml_pos_t toml_pos_t;
|
||||
|
||||
// TOML table.
|
||||
struct toml_table_t {
|
||||
const char* key; // Key for this table
|
||||
int keylen; // length of key.
|
||||
bool implicit; // Table was created implicitly
|
||||
bool readonly; // No more modification allowed
|
||||
|
||||
int nkval; // key-values in the table
|
||||
toml_keyval_t** kval;
|
||||
int narr; // arrays in the table
|
||||
toml_array_t** arr;
|
||||
int ntbl; // tables in the table
|
||||
toml_table_t** tbl;
|
||||
};
|
||||
|
||||
// TOML array.
|
||||
struct toml_array_t {
|
||||
const char* key; // key to this array
|
||||
int keylen; // length of key.
|
||||
int kind; // element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed
|
||||
int type; // for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed
|
||||
int nitem; // number of elements
|
||||
toml_arritem_t* item;
|
||||
};
|
||||
struct toml_arritem_t {
|
||||
int valtype; // for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp
|
||||
char* val;
|
||||
toml_array_t* arr;
|
||||
toml_table_t* tbl;
|
||||
};
|
||||
|
||||
// TOML key/value pair.
|
||||
struct toml_keyval_t {
|
||||
const char* key; // key to this value
|
||||
int keylen; // length of key.
|
||||
const char* val; // the raw value
|
||||
};
|
||||
|
||||
// Token position.
|
||||
struct toml_pos_t {
|
||||
int line;
|
||||
int col;
|
||||
};
|
||||
|
||||
// Timestamp type; some values may be empty depending on the value of kind.
|
||||
struct toml_timestamp_t {
|
||||
// datetime type:
|
||||
//
|
||||
// 'd'atetime Full date + time + TZ
|
||||
// 'l'local-datetime Full date + time but without TZ
|
||||
// 'D'ate-local Date only, without TZ
|
||||
// 't'ime-local Time only, without TZ
|
||||
char kind;
|
||||
|
||||
int year, month, day;
|
||||
int hour, minute, second, millisec;
|
||||
int tz; // Timezone offset in minutes
|
||||
};
|
||||
|
||||
// Parsed TOML value.
|
||||
//
|
||||
// The string value s is a regular NULL-terminated C string, but the string
|
||||
// length is also given in sl since TOML values may contain NULL bytes. The
|
||||
// value is guaranteed to be correct UTF-8.
|
||||
struct toml_value_t {
|
||||
bool ok; // Was this value present?
|
||||
union {
|
||||
struct {
|
||||
char* s; // string value; must be freed after use.
|
||||
int sl; // string length, excluding NULL.
|
||||
};
|
||||
toml_timestamp_t ts; // datetime
|
||||
bool b; // bool
|
||||
int64_t i; // int
|
||||
double d; // double
|
||||
} u;
|
||||
};
|
||||
|
||||
// toml_parse() parses a TOML document from a string. Returns 0 on error, with
|
||||
// the error message stored in errbuf.
|
||||
//
|
||||
// toml_parse_file() is identical, but reads from a file descriptor.
|
||||
//
|
||||
// Use toml_free() to free the return value; this will invalidate all handles
|
||||
// for this table.
|
||||
TOML_EXTERN toml_table_t* toml_parse(char* toml, char* errbuf, int errbufsz);
|
||||
TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, char* errbuf, int errbufsz);
|
||||
TOML_EXTERN void toml_free(toml_table_t* table);
|
||||
|
||||
// Table functions.
|
||||
//
|
||||
// toml_table_len() gets the number of direct keys for this table;
|
||||
// toml_table_key() gets the nth direct key in this table.
|
||||
TOML_EXTERN int toml_table_len(const toml_table_t* table);
|
||||
TOML_EXTERN const char* toml_table_key(const toml_table_t* table, int keyidx, int* keylen);
|
||||
TOML_EXTERN toml_value_t toml_table_string(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_bool(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_int(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_double(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_timestamp(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_array_t* toml_table_array(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_table_t* toml_table_table(const toml_table_t* table, const char* key);
|
||||
|
||||
// Array functions.
|
||||
TOML_EXTERN int toml_array_len(const toml_array_t* array);
|
||||
TOML_EXTERN toml_value_t toml_array_string(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_bool(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_int(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_double(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_timestamp(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_array_t* toml_array_array(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_table_t* toml_array_table(const toml_array_t* array, int idx);
|
||||
|
||||
#endif // TOML_H
|
||||
301
src/common/toml/toml.nim
Normal file
301
src/common/toml/toml.nim
Normal file
@@ -0,0 +1,301 @@
|
||||
import random, strutils
|
||||
|
||||
# Wrapper for the toml-c library
|
||||
# Original: github.com/arp242/toml-c/
|
||||
|
||||
{.compile: "toml.c".}
|
||||
|
||||
type
|
||||
TomlKeyVal = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
val: cstring
|
||||
|
||||
TomlArrItem = object
|
||||
valtype: cint
|
||||
val: cstring
|
||||
arr: ptr TomlArray
|
||||
tbl: ptr TomlTable
|
||||
|
||||
TomlTable = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
implicit: bool
|
||||
readonly: bool
|
||||
nkval: cint
|
||||
kval: ptr ptr TomlKeyVal
|
||||
narr: cint
|
||||
arr: ptr ptr TomlArray
|
||||
ntbl: cint
|
||||
tbl: ptr ptr TomlTable
|
||||
|
||||
TomlArray = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
kind: cint
|
||||
`type`: cint
|
||||
nitem: cint
|
||||
item: ptr TomlArrItem
|
||||
|
||||
TomlValue = object
|
||||
case ok: bool
|
||||
of false: discard
|
||||
of true:
|
||||
s: cstring
|
||||
sl: cint
|
||||
|
||||
TomlTableRef* = ptr TomlTable
|
||||
|
||||
TomlValueKind* = enum
|
||||
String, Int, Bool, Float, Table, Array, None
|
||||
|
||||
TomlValueRef* = ref object
|
||||
case kind*: TomlValueKind
|
||||
of String:
|
||||
strVal*: string
|
||||
of Int:
|
||||
intVal*: int64
|
||||
of Bool:
|
||||
boolVal*: bool
|
||||
of Float:
|
||||
floatVal*: float64
|
||||
of Table:
|
||||
tableVal*: TomlTableRef
|
||||
of Array:
|
||||
arrayVal*: ptr TomlArray
|
||||
of None:
|
||||
discard
|
||||
|
||||
# C library functions
|
||||
proc toml_parse(toml: cstring, errbuf: cstring, errbufsz: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_parse_file(fp: File, errbuf: cstring, errbufsz: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_free(tab: TomlTableRef) {.importc, cdecl.}
|
||||
proc toml_table_len(tab: TomlTableRef): cint {.importc, cdecl.}
|
||||
proc toml_table_key(tab: TomlTableRef, keyidx: cint, keylen: ptr cint): cstring {.importc, cdecl.}
|
||||
proc toml_table_string(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_int(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_bool(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_double(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_array(tab: TomlTableRef, key: cstring): ptr TomlArray {.importc, cdecl.}
|
||||
proc toml_table_table(tab: TomlTableRef, key: cstring): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_array_len(arr: ptr TomlArray): cint {.importc, cdecl.}
|
||||
proc toml_array_table(arr: ptr TomlArray, idx: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_array_string(arr: ptr TomlArray, idx: cint): TomlValue {.importc, cdecl.}
|
||||
proc toml_array_int(arr: ptr TomlArray, idx: cint): TomlValue {.importc, cdecl.}
|
||||
|
||||
#[
|
||||
Retrieve a random element from a TOML array
|
||||
]#
|
||||
proc getRandom*(arr: ptr TomlArray): TomlValueRef =
|
||||
if arr.isNil:
|
||||
return nil
|
||||
|
||||
let n = toml_array_len(arr)
|
||||
if n == 0:
|
||||
return nil
|
||||
|
||||
let idx = rand(n.int - 1)
|
||||
|
||||
# String
|
||||
let strVal {.volatile.} = toml_array_string(arr, idx.cint)
|
||||
if strVal.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr strVal) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
# Table
|
||||
let table {.volatile.} = toml_array_table(arr, idx.cint)
|
||||
if not table.isNil:
|
||||
return TomlValueRef(kind: Table, tableVal: table)
|
||||
|
||||
# Int
|
||||
let intVal {.volatile.} = toml_array_int(arr, idx.cint)
|
||||
if intVal.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr intVal) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
return nil
|
||||
|
||||
#[
|
||||
Parse TOML string or configuration file
|
||||
]#
|
||||
proc parseString*(toml: string): TomlTableRef =
|
||||
var errbuf: array[200, char]
|
||||
|
||||
var tomlCopy = toml
|
||||
result = toml_parse(tomlCopy.cstring, cast[cstring](addr errbuf[0]), 200)
|
||||
|
||||
if result.isNil:
|
||||
raise newException(ValueError, "TOML parse error: " & $cast[cstring](addr errbuf[0]))
|
||||
|
||||
proc parseFile*(path: string): TomlTableRef =
|
||||
var errbuf: array[200, char]
|
||||
let fp = open(path, fmRead)
|
||||
if fp.isNil:
|
||||
raise newException(IOError, "Cannot open file: " & path)
|
||||
|
||||
result = toml_parse_file(fp, cast[cstring](addr errbuf[0]), 200)
|
||||
fp.close()
|
||||
|
||||
if result.isNil:
|
||||
raise newException(ValueError, "TOML parse error: " & $cast[cstring](addr errbuf[0]))
|
||||
|
||||
proc free*(table: TomlTableRef) =
|
||||
if not table.isNil:
|
||||
toml_free(table)
|
||||
|
||||
#[
|
||||
Takes a specific "."-separated path as input and returns the TOML Value that it finds
|
||||
]#
|
||||
proc findKey*(profile: TomlTableRef, path: string): TomlValueRef =
|
||||
if profile.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
let keys = path.split(".")
|
||||
var current = profile
|
||||
|
||||
# Navigate through nested tables
|
||||
for i in 0 ..< keys.len - 1:
|
||||
let nextTable = toml_table_table(current, keys[i].cstring)
|
||||
if nextTable.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
current = nextTable
|
||||
|
||||
let finalKey = keys[^1].cstring
|
||||
|
||||
# Try different types
|
||||
# {.volatile.} is added to avoid dangling pointers
|
||||
block findStr:
|
||||
let val {.volatile.} = toml_table_string(current, finalKey)
|
||||
if val.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr val) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
block checkInt:
|
||||
let val {.volatile.} = toml_table_int(current, finalKey)
|
||||
if val.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
block checkBool:
|
||||
let val {.volatile.} = toml_table_bool(current, finalKey)
|
||||
if val.ok:
|
||||
let boolPtr = cast[ptr bool](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Bool, boolVal: boolPtr)
|
||||
|
||||
block checkDouble:
|
||||
let val {.volatile.} = toml_table_double(current, finalKey)
|
||||
if val.ok:
|
||||
let dblPtr = cast[ptr float64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Float, floatVal: dblPtr)
|
||||
|
||||
block checkArray:
|
||||
let arr {.volatile.} = toml_table_array(current, finalKey)
|
||||
if not arr.isNil:
|
||||
return TomlValueRef(kind: Array, arrayVal: arr)
|
||||
|
||||
block checkTable:
|
||||
let table {.volatile.} = toml_table_table(current, finalKey)
|
||||
if not table.isNil:
|
||||
return TomlValueRef(kind: Table, tableVal: table)
|
||||
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
#[
|
||||
Retrieve the actual value from a TOML value
|
||||
]#
|
||||
proc getStr*(value: TomlValueRef, default: string = ""): string =
|
||||
if value.kind == String:
|
||||
return value.strVal
|
||||
return default
|
||||
|
||||
proc getInt*(value: TomlValueRef, default: int = 0): int =
|
||||
if value.kind == Int:
|
||||
return value.intVal.int
|
||||
return default
|
||||
|
||||
proc getBool*(value: TomlValueRef, default: bool = false): bool =
|
||||
if value.kind == Bool:
|
||||
return value.boolVal
|
||||
return default
|
||||
|
||||
proc getTable*(value: TomlValueRef): TomlTableRef =
|
||||
if value.kind == Table:
|
||||
return value.tableVal
|
||||
return nil
|
||||
|
||||
proc getElems*(value: TomlValueRef): seq[TomlValueRef] =
|
||||
if value.kind != Array:
|
||||
return @[]
|
||||
|
||||
let arr = value.arrayVal
|
||||
let n = toml_array_len(arr)
|
||||
result = @[]
|
||||
|
||||
for i in 0 ..< n:
|
||||
# Try table first
|
||||
let table {.volatile.} = toml_array_table(arr, i.cint)
|
||||
if not table.isNil:
|
||||
result.add(TomlValueRef(kind: Table, tableVal: table))
|
||||
continue
|
||||
|
||||
# Try string
|
||||
let strVal = toml_array_string(arr, i.cint)
|
||||
if strVal.ok:
|
||||
let strPtr {.volatile.} = cast[ptr cstring](cast[int](addr strVal) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
result.add(TomlValueRef(kind: String, strVal: $strPtr))
|
||||
continue
|
||||
|
||||
# Try int
|
||||
let intVal = toml_array_int(arr, i.cint)
|
||||
if intVal.ok:
|
||||
let intPtr {.volatile.} = cast[ptr int64](cast[int](addr intVal) + 8)[]
|
||||
result.add(TomlValueRef(kind: Int, intVal: intPtr))
|
||||
|
||||
proc getTableKeys*(profile: TomlTableRef, path: string): seq[tuple[key: string, value: TomlValueRef]] =
|
||||
result = @[]
|
||||
let key = profile.findKey(path)
|
||||
let table = key.getTable()
|
||||
if table.isNil:
|
||||
return
|
||||
|
||||
let numKeys = toml_table_len(table)
|
||||
for i in 0 ..< numKeys:
|
||||
var keylen: cint
|
||||
let keyPtr = toml_table_key(table, i.cint, addr keylen)
|
||||
if keyPtr.isNil:
|
||||
continue
|
||||
|
||||
let key = $keyPtr
|
||||
let value = profile.findKey(path & "." & key)
|
||||
if value.kind != None:
|
||||
result.add((key: key, value: value))
|
||||
|
||||
proc getTableValue*(table: TomlTableRef, key: string): TomlValueRef =
|
||||
if table.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
let ckey = key.cstring
|
||||
|
||||
block checkString:
|
||||
let val {.volatile.} = toml_table_string(table, ckey)
|
||||
if val.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr val) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
block checkInt:
|
||||
let val {.volatile.} = toml_table_int(table, ckey)
|
||||
if val.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
block checkBool:
|
||||
let val {.volatile.} = toml_table_bool(table, ckey)
|
||||
if val.ok:
|
||||
let boolPtr = cast[ptr bool](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Bool, boolVal: boolPtr)
|
||||
|
||||
return TomlValueRef(kind: None)
|
||||
@@ -1,10 +1,12 @@
|
||||
import tables
|
||||
import parsetoml, json
|
||||
import json
|
||||
import system
|
||||
import mummy
|
||||
when defined(client):
|
||||
import whisky
|
||||
|
||||
import ./toml/toml
|
||||
|
||||
# Custom Binary Task structure
|
||||
const
|
||||
MAGIC* = 0x514E3043'u32 # Magic value: C0NQ
|
||||
@@ -285,7 +287,7 @@ type
|
||||
privateKey*: Key
|
||||
publicKey*: Key
|
||||
|
||||
Profile* = TomlValueRef
|
||||
Profile* = TomlTableRef
|
||||
|
||||
WsConnection* = ref object
|
||||
when defined(server):
|
||||
@@ -300,6 +302,7 @@ type
|
||||
threads*: Table[string, Thread[Listener]]
|
||||
agents*: Table[string, Agent]
|
||||
keyPair*: KeyPair
|
||||
profileString*: string
|
||||
profile*: Profile
|
||||
client*: WsConnection
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mummy, terminal, parsetoml, tables
|
||||
import strutils, strformat, base64
|
||||
import mummy, terminal
|
||||
import strutils, strformat
|
||||
|
||||
import ./handlers
|
||||
import ../globals
|
||||
@@ -81,8 +81,8 @@ proc httpGet*(request: Request) =
|
||||
|
||||
# Add headers, as defined in the team server profile
|
||||
var headers: HttpHeaders
|
||||
for header, value in cq.profile.getTable("http-get.server.headers"):
|
||||
headers.add((header, value.getStringValue()))
|
||||
for header in cq.profile.getTableKeys("http-get.server.headers"):
|
||||
headers.add((header.key, header.value.getStringValue()))
|
||||
|
||||
request.respond(200, headers = headers, body = payload)
|
||||
|
||||
@@ -129,8 +129,8 @@ proc httpPost*(request: Request) =
|
||||
|
||||
# Add response headers, as defined in team server profile
|
||||
var headers: HttpHeaders
|
||||
for header, value in cq.profile.getTable("http-post.server.headers"):
|
||||
headers.add((header, value.getStringValue()))
|
||||
for header in cq.profile.getTableKeys("http-post.server.headers"):
|
||||
headers.add((header.key, header.value.getStringValue()))
|
||||
|
||||
# Differentiate between registration and task result packet
|
||||
var unpacker = Unpacker.init(Bytes.toString(data))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import terminal, strformat, strutils, sequtils, tables, system, osproc, streams, parsetoml
|
||||
import terminal, strformat, strutils, sequtils, tables, system, osproc, streams
|
||||
|
||||
import ../globals
|
||||
import ../core/[logger, websocket]
|
||||
@@ -38,7 +38,7 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: Sle
|
||||
packer.addData(cq.keyPair.publicKey)
|
||||
|
||||
# C2 profile
|
||||
packer.addDataWithLengthPrefix(string.toBytes(cq.profile.toTomlString()))
|
||||
packer.addDataWithLengthPrefix(string.toBytes(cq.profileString))
|
||||
|
||||
let data = packer.pack()
|
||||
packer.reset()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import strformat, strutils, terminal
|
||||
import strformat, strutils, terminal, tables
|
||||
import mummy, mummy/routers
|
||||
import parsetoml
|
||||
|
||||
import ../api/routes
|
||||
import ../db/database
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import times, json, base64, parsetoml, strformat
|
||||
import times, json, base64, strformat
|
||||
import stb_image/write as stbiw
|
||||
import ./logger
|
||||
import ../../common/[types, utils, event]
|
||||
@@ -46,12 +46,12 @@ proc sendPublicKey*(client: WsConnection, publicKey: Key) =
|
||||
if client != nil:
|
||||
client.ws.sendEvent(event, client.sessionKey)
|
||||
|
||||
proc sendProfile*(client: WsConnection, profile: Profile) =
|
||||
proc sendProfile*(client: WsConnection, profileString: string) =
|
||||
let event = Event(
|
||||
eventType: CLIENT_PROFILE,
|
||||
timestamp: now().toTime().toUnix(),
|
||||
data: %*{
|
||||
"profile": profile.toTomlString()
|
||||
"profile": profileString
|
||||
}
|
||||
)
|
||||
if client != nil:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mummy, mummy/routers
|
||||
import terminal, parsetoml, json, math, base64, times
|
||||
import terminal, json, math, base64, times
|
||||
import strutils, strformat, system, tables
|
||||
|
||||
import ./globals
|
||||
@@ -15,14 +15,15 @@ proc header() =
|
||||
echo "─".repeat(21)
|
||||
echo ""
|
||||
|
||||
proc init*(T: type Conquest, profile: Profile): Conquest =
|
||||
proc init*(T: type Conquest, profileString: string): Conquest =
|
||||
var cq = new Conquest
|
||||
cq.listeners = initTable[string, Listener]()
|
||||
cq.threads = initTable[string, Thread[Listener]]()
|
||||
cq.agents = initTable[string, Agent]()
|
||||
cq.profile = profile
|
||||
cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & profile.getString("private-key-file"))
|
||||
cq.dbPath = CONQUEST_ROOT & "/" & profile.getString("database-file")
|
||||
cq.profileString = profileString
|
||||
cq.profile = parseString(profileString)
|
||||
cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & cq.profile.getString("private-key-file"))
|
||||
cq.dbPath = CONQUEST_ROOT & "/" & cq.profile.getString("database-file")
|
||||
cq.client = nil
|
||||
return cq
|
||||
|
||||
@@ -54,7 +55,7 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.
|
||||
|
||||
# Send relevant information to the client
|
||||
# C2 profile
|
||||
cq.client.sendProfile(cq.profile)
|
||||
cq.client.sendProfile(cq.profileString)
|
||||
|
||||
# Listeners
|
||||
for id, listener in cq.listeners:
|
||||
@@ -140,11 +141,10 @@ proc startServer*(profilePath: string) =
|
||||
|
||||
try:
|
||||
# Initialize framework context
|
||||
# Load and parse profile
|
||||
let profile = parsetoml.parseFile(profilePath)
|
||||
cq = Conquest.init(profile)
|
||||
let profileString = readFile(profilePath)
|
||||
cq = Conquest.init(profileString)
|
||||
|
||||
cq.info("Using profile \"", profile.getString("name"), "\" (", profilePath ,").")
|
||||
cq.info("Using profile \"", cq.profile.getString("name"), "\" (", profilePath ,").")
|
||||
|
||||
# Initialize database
|
||||
cq.dbInit()
|
||||
|
||||
Reference in New Issue
Block a user