729 const std::string key = extract_activation_key(raw_key);
731 status.
message =
"No activation key installed.";
735 const auto apply_common_field_checks = [&](
const std::string& product,
736 const std::string& key_machine_raw,
737 const std::string& key_motherboard_raw,
738 const std::string& owner,
739 const std::string& edition,
740 const std::string& expires) ->
bool {
741 if (product != kProductId) {
742 status.
message =
"Activation key is for a different product.";
746 if (key_machine_raw.empty()) {
747 status.
message =
"Activation key does not contain a Machine ID.";
751 if (key_motherboard_raw.empty()) {
752 status.
message =
"Activation key does not contain a motherboard serial.";
757 status.
message =
"Motherboard serial could not be read on this computer.";
761 const std::string key_machine = compact_hex_machine_id(key_machine_raw);
762 const std::string current_machine = compact_hex_machine_id(status.
machine_id);
763 const std::string legacy_machine = compact_hex_machine_id(legacy_application_machine_id());
765 if (key_machine != current_machine && key_machine != legacy_machine) {
766 status.
message =
"Activation key is for a different machine-id.";
770 const std::string key_motherboard = canonical_serial(key_motherboard_raw);
773 if (key_motherboard != current_motherboard) {
774 status.
message =
"Activation key is for a different motherboard serial.";
778 status.
owner = owner.empty() ?
"Donation supporter" : owner;
779 status.
edition = edition.empty() ?
"Donation" : edition;
780 status.
expires = expires.empty() ?
"never" : lowercase(expires);
782 if (!is_valid_expiry(status.
expires)) {
784 status.
message =
"Activation key contains an invalid expiry date.";
788 if (has_expired(status.
expires)) {
790 status.
message =
"Activation key has expired.";
795 status.
message =
"Activation is valid.";
804 if (key.find(std::string(kKeyPrefixV3)) != std::string::npos) {
805 const auto fields = parse_key_block(key);
806 const std::string code = normalize_activation_code(field_or_empty(fields,
"CODE"));
807 const std::string product = trim(field_or_empty(fields,
"PRODUCT"));
808 const std::string engine = normalize_engine_id(field_or_empty(fields,
"ENGINE"));
809 const std::string machine = compact_hex_machine_id(field_or_empty(fields,
"MACHINE"));
810 const std::string motherboard = canonical_serial(field_or_empty(fields,
"MOTHERBOARD"));
811 const std::string owner = trim(field_or_empty(fields,
"OWNER"));
812 const std::string edition = trim(field_or_empty(fields,
"EDITION"));
813 const std::string expires = lowercase(trim(field_or_empty(fields,
"EXPIRES")));
815 if (field_or_empty(fields,
"FORMAT") != std::string(kKeyPrefixV3)) {
816 status.
message =
"Invalid BGRD3 activation key: BGRD3 format line is missing.";
820 if (code.size() != 25) {
821 status.
message =
"Invalid BGRD3 activation key: CODE must contain 25 letters/numbers.";
825 if (engine.empty()) {
826 status.
message =
"Invalid BGRD3 activation key: ENGINE field is missing.";
831 if (normalize_engine_id(engine) != current_engine) {
832 status.
message =
"Activation engine mismatch. App engine is " + current_engine +
833 " but key engine is " + engine +
834 ". Rebuild and reinstall the app and generate the keygen from the same package.";
838 const std::string canonical_payload = code_payload_v3(fields);
839 const std::string expected_code = normalize_activation_code(generate_activation_code_v3(canonical_payload));
840 if (code != expected_code) {
841 status.
message =
"BGRD3 activation code is not valid. The key was not saved. Generate the key again with the matching keygen and copy the whole BEGIN/END block.";
845 apply_common_field_checks(product, machine, motherboard, owner, edition, expires);
852 if (key.find(std::string(kKeyPrefixV2)) != std::string::npos) {
853 const auto fields = parse_key_block(key);
854 const std::string signature = uppercase(trim(field_or_empty(fields,
"SIGNATURE")));
855 const std::string product = trim(field_or_empty(fields,
"PRODUCT"));
856 const std::string engine = normalize_engine_id(field_or_empty(fields,
"ENGINE"));
857 const std::string machine = compact_hex_machine_id(field_or_empty(fields,
"MACHINE"));
858 const std::string motherboard = canonical_serial(field_or_empty(fields,
"MOTHERBOARD"));
859 const std::string owner = trim(field_or_empty(fields,
"OWNER"));
860 const std::string edition = trim(field_or_empty(fields,
"EDITION"));
861 const std::string expires = lowercase(trim(field_or_empty(fields,
"EXPIRES")));
863 if (signature.size() != 40) {
864 status.
message =
"Invalid BGRD2 activation key: SIGNATURE must contain 40 hexadecimal characters.";
867 for (
unsigned char c : signature) {
868 if (std::isxdigit(c) == 0) {
869 status.
message =
"Invalid BGRD2 activation key: SIGNATURE contains a non-hexadecimal character.";
874 if (engine.empty()) {
875 status.
message =
"Invalid BGRD2 activation key: ENGINE field is missing.";
880 if (normalize_engine_id(engine) != current_engine) {
881 status.
message =
"Activation engine mismatch. App engine is " + current_engine +
882 " but key engine is " + engine +
883 ". Rebuild and reinstall the app and generate the keygen from the same package.";
887 const std::string canonical_payload = canonical_v2_payload(fields);
888 const std::string expected_signature = sign_payload_v2(canonical_payload);
889 if (signature != expected_signature) {
890 status.
message =
"BGRD2 activation key signature is not valid. The key was not saved. Generate the key again with the matching keygen and copy the whole BEGIN/END block.";
894 apply_common_field_checks(product, machine, motherboard, owner, edition, expires);
899 const std::string prefix = std::string(kKeyPrefixV1) +
".";
900 if (key.rfind(prefix, 0) != 0) {
901 status.
message =
"Invalid activation key prefix. Paste a BGRD3 activation block generated by the matching keygen.";
905 const auto first_dot = key.find(
'.', prefix.size());
906 if (first_dot == std::string::npos) {
907 status.
message =
"Malformed legacy activation key.";
911 const std::string payload_b64 = key.substr(prefix.size(), first_dot - prefix.size());
912 const std::string signature = uppercase(key.substr(first_dot + 1));
914 if (signature.size() != 40) {
915 status.
message =
"Invalid legacy activation key signature length.";
919 const auto decoded_payload = base64url_decode(payload_b64);
920 if (!decoded_payload.has_value()) {
921 status.
message =
"Legacy activation key payload is not valid base64url.";
925 const std::string expected_signature = sign_payload_v1(*decoded_payload);
926 if (signature != expected_signature) {
927 status.
message =
"Legacy activation key signature is not valid. Generate a new BGRD3 key with the matching keygen.";
931 const auto fields = parse_payload(*decoded_payload);
932 const auto product_it = fields.find(
"product");
933 const auto machine_it = fields.find(
"machine");
934 const auto motherboard_it = fields.find(
"motherboard");
935 const auto owner_it = fields.find(
"owner");
936 const auto edition_it = fields.find(
"edition");
937 const auto expires_it = fields.find(
"expires");
939 apply_common_field_checks(
940 product_it != fields.end() ? product_it->second : std::string{},
941 machine_it != fields.end() ? machine_it->second : std::string{},
942 motherboard_it != fields.end() ? motherboard_it->second : std::string{},
943 owner_it != fields.end() ? owner_it->second : std::string{},
944 edition_it != fields.end() ? edition_it->second : std::string{},
945 expires_it != fields.end() ? expires_it->second : std::string{}