#
Generate Fingerprint
So, if you have visited the previous page containing Fingerprint object schema, you already know it's quite
cumbersome.
Luckily, there is an easier way to do it.
We have implemented fingerprint generation logic into our tool -
aemulari
, which generates fingerprint
just the same way as Surfinite App does it when you click Generate
button on a profile page. The command for
this is generate-fp
. Here's the help message:
$ ./aemulari generate-fp --help
Generate fingerprint usage:
--os TEXT Operating System (required), allowed values: "windows",
"linux", "macos"
--os-version TEXT OS version (optional). For Windows: "7", "8", "8.1",
"10" and "11". For macOS: "11" (Big
Sur), "12" (Monterey) and "13" (Ventura). For Linux it must be kernel
version string like "5.15.0". Defaults: "10" for
Windows, "13" for macOS and "5.15.0" for Linux
--chrome-version TEXT Full Chrome version (optional, recommended), e.g.
"106.0.5249.134". Default: the newest version packed
with this version of aemulari. Might be outdated
--pretty Prettify JSON. Might be very handy for manual use when
testing
This command generates fingerprint object with the same logic as in Surfinite App and returns JSON as its output.
Try it yourself
Just hop into your terminal or CMD and try it yourself. You can use --pretty
flag to make the output readable.
You would then use it to create your profile. Or first set some custom fields (like change screen or disable WebGL) and then create profile. Here's a code example:
// Start aemulari to generate fingerprint
val process = ProcessBuilder(
listOf(
"/home/myuser/.surfinite/aemulari/aemulari",
"generate-fp",
"--os", "windows", // required
"--os-version", "10", // optional
"--chrome-version", "106.0.5249.134" // optional
)
)
.start()
// Read output. It is either fingerprint string or an error
val procOutput = process.inputStream.readAllBytes().decodeToString()
process.waitFor()
val exitCode = process.exitValue()
if (exitCode != 0) {
println("Generate Fingerprint error. Exit code: $exitCode.")
println(procOutput) // should contain error from aemulari
return
}
// Create request JSON
val fingerprintObject = Json.parseToJsonElement(procOutput)
val clusterId = "62aad24955d7cb159cae7fae"
val profileRequest: JsonObject = buildJsonObject {
put("parentId", clusterId) // you can also set group as parent
put("name", "Test Profile")
put("fingerprint", fingerprintObject)
}
val client = HttpClient(CIO) {
install(ContentNegotiation) { json() }
}
// Create profile request
val response = client
.post("$apiUrl/profiles?api_key=$apiKey") {
contentType(ContentType.Application.Json)
setBody(profileRequest)
}
.body<JsonObject>()
// Server returns profile object, so you can use it further
// in your app logic.
println("Profile ID: ${response["_id"]!!.jsonPrimitive}")
The command is completely offline, no requests are made to our servers.
The only error you can come up with it, is if you pass an incorrect argument, e.g. --os=wind0ws
. The program
would exit with code 1
in this case and an error message printed to stdout
.