# 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.

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}")