136 lines
5.2 KiB
Nim
136 lines
5.2 KiB
Nim
import strutils, sequtils, random, base64, algorithm
|
|
import ./[types, utils]
|
|
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 (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)]
|
|
|
|
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)]
|
|
|
|
#[
|
|
Wrapper functions
|
|
]#
|
|
proc getStringValue*(key: TomlValueRef, default: string = ""): string =
|
|
if key.isNil or key.kind == None:
|
|
return default
|
|
|
|
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 =
|
|
let key = profile.findKey(path)
|
|
return key.getStringValue(default)
|
|
|
|
proc getInt*(profile: Profile, path: string, default: int = 0): int =
|
|
let key = profile.findKey(path)
|
|
return key.getInt(default)
|
|
|
|
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)
|
|
return key.getTable()
|
|
|
|
proc getArray*(profile: Profile, path: string): seq[TomlValueRef] =
|
|
let key = profile.findKey(path)
|
|
if key.kind != Array:
|
|
return @[]
|
|
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 steps: seq[TomlTableRef] = @[]
|
|
|
|
# Apply all encoding techniques in the order specified in the profile
|
|
if profile.isArray(path & protect(".encoding")):
|
|
for encoding in profile.getArray(path & protect(".encoding")):
|
|
steps.add(encoding.getTable())
|
|
else:
|
|
steps = @[profile.getTable(path & protect(".encoding"))]
|
|
|
|
var dataString: string = Bytes.toString(data)
|
|
for step in steps:
|
|
case step.getTableValue(protect("type")).getStr(default = "none")
|
|
of protect("base64"):
|
|
dataString = encode(dataString, safe = step.getTableValue(protect("url-safe")).getBool()).replace("=", "")
|
|
of protect("hex"):
|
|
dataString = dataString.toHex().toLowerAscii()
|
|
of protect("rot"):
|
|
dataString = Bytes.toString(encodeRot(string.toBytes(dataString), step.getTableValue(protect("key")).getInt(default = 13)))
|
|
of protect("xor"):
|
|
dataString = Bytes.toString(xorBytes(string.toBytes(dataString), step.getTableValue(protect("key")).getInt(default = 1)))
|
|
of protect("none"):
|
|
discard
|
|
|
|
# 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"))
|
|
var dataString = data[len(prefix) ..^ len(suffix) + 1]
|
|
|
|
# 2. Decoding
|
|
var steps: seq[TomlTableRef] = @[]
|
|
|
|
# Apply all encoding techniques in reverse order
|
|
if profile.isArray(path & protect(".encoding")):
|
|
for encoding in profile.getArray(path & protect(".encoding")):
|
|
steps.add(encoding.getTable())
|
|
else:
|
|
steps = @[profile.getTable(path & protect(".encoding"))]
|
|
|
|
for step in steps.reversed():
|
|
case step.getTableValue(protect("type")).getStr(default = "none")
|
|
of protect("base64"):
|
|
dataString = decode(dataString)
|
|
of protect("hex"):
|
|
dataString = parseHexStr(dataString)
|
|
of protect("rot"):
|
|
dataString = Bytes.toString(decodeRot(string.toBytes(dataString), step.getTableValue(protect("key")).getInt(default = 13)))
|
|
of protect("xor"):
|
|
dataString = Bytes.toString(xorBytes(string.toBytes(dataString), step.getTableValue(protect("key")).getInt(default = 1)))
|
|
of protect("none"):
|
|
discard
|
|
|
|
return string.toBytes(dataString) |