Files
conquest/src/common/profile.nim

111 lines
4.1 KiB
Nim
Raw Normal View History

import parsetoml, 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)
# 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
proc randomChar(): char =
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return alphabet[rand(alphabet.len - 1)]
2025-11-12 19:50:57 +01:00
proc randomNumber(): char =
let numbers = "0123456789"
return numbers[rand(numbers.len - 1)]
proc getRandom*(values: seq[TomlValueRef]): TomlValueRef =
if values.len == 0:
return nil
return values[rand(values.len - 1)]
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)
# Replace '#' with a random alphanumerical character and return the resulting string
2025-11-12 19:50:57 +01:00
return value.mapIt(if it == '#': randomChar() elif it == '$': randomNumber() else: it).join("")
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 =
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 =
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:
return @[]
return key.getElems()
proc applyDataTransformation*(profile: Profile, path: string, data: seq[byte]): string =
var dataString: string
# 1. Encoding
case profile.getString(path & protect(".encoding.type"), default = protect("none"))
of protect("base64"):
dataString = encode(data, safe = profile.getBool(path & protect(".encoding.url-safe"))).replace("=", "")
of protect("hex"):
dataString = Bytes.toString(data).toHex().toLowerAscii()
of protect("none"):
dataString = Bytes.toString(data)
# 2. Add prefix & suffix
let prefix = profile.getString(path & protect(".prefix"))
let suffix = profile.getString(path & protect(".suffix"))
return prefix & dataString & suffix
proc reverseDataTransformation*(profile: Profile, path: string, data: string): seq[byte] =
# 1. Remove prefix & suffix
let
prefix = profile.getString(path & protect(".prefix"))
suffix = profile.getString(path & protect(".suffix"))
dataString = data[len(prefix) ..^ len(suffix) + 1]
# 2. Decoding
case profile.getString(path & protect(".encoding.type"), default = protect("none")):
of protect("base64"):
result = string.toBytes(decode(dataString))
of protect("hex"):
result = string.toBytes(parseHexStr(dataString))
of protect("none"):
result = string.toBytes(dataString)