{ "name": "Validate a TOTP Code", "nodes": [ { "id": "validate-a-totp-code-0", "name": "When clicking ‘Test workflow’", "type": "n8n-nodes-base.manualTrigger", "position": [ 480, 680 ], "parameters": {}, "typeVersion": 1 }, { "id": "validate-a-totp-code-1", "name": "TOTP VALIDATION", "type": "n8n-nodes-base.code", "position": [ 920, 680 ], "parameters": { "language": "python", "pythonCode": "import hmac\nimport hashlib\nimport time\nimport base64\n\ndef base32_decode(key):\n \"\"\"Decodes a base32 key into bytes\"\"\"\n key += '=' * (-len(key) % 8) # Add necessary '=' for valid length\n return base64.b32decode(key.upper(), casefold=True)\n\ndef generate_totp(secret, interval=30, digits=6):\n \"\"\"Generates a TOTP code based on a secret key\"\"\"\n interval_count = int(time.time() // interval)\n interval_bytes = interval_count.to_bytes(8, byteorder='big')\n\n hmac_hash = hmac.new(secret, interval_bytes, hashlib.sha1).digest()\n \n offset = hmac_hash[-1] & 0x0F\n binary_code = ((hmac_hash[offset] & 0x7F) << 24 |\n (hmac_hash[offset + 1] & 0xFF) << 16 |\n (hmac_hash[offset + 2] & 0xFF) << 8 |\n (hmac_hash[offset + 3] & 0xFF))\n \n otp_code = binary_code % (10 ** digits)\n \n # Format with leading zeros if necessary\n otp_code_str = str(otp_code).zfill(digits)\n \n return otp_code_str\n\ndef verify_totp(secret, code, interval=30, digits=6):\n \"\"\"Checks whether the TOTP code is valid\"\"\"\n secret_bytes = base32_decode(secret)\n generated_code = generate_totp(secret_bytes, interval, digits)\n \n return generated_code == code\n\n# Example of use\nsecret = _input.item.json.totp_secret_example # Secret key base32 (example)\ncode = _input.item.json.code_to_verify_example # Code to check (example)\n\n# Return 1 if code is valid. Return 0 if invalid\nif verify_totp(secret, code):\n return [{\"status\": 1}]\nelse:\n return [{\"status\": 0}]" }, "typeVersion": 2 }, { "id": "validate-a-totp-code-2", "name": "IF CODE IS VALID", "type": "n8n-nodes-base.if", "position": [ 1140, 680 ], "parameters": { "options": {}, "conditions": { "options": { "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "combinator": "and", "conditions": [ { "id": "470cf368-daee-4136-b907-a3539765871d", "operator": { "type": "number", "operation": "equals" }, "leftValue": "={{ $json.status }}", "rightValue": 1 } ] } }, "typeVersion": 2.1 }, { "id": "validate-a-totp-code-3", "name": "EXAMPLE FIELDS", "type": "n8n-nodes-base.set", "position": [ 700, 680 ], "parameters": { "options": {}, "assignments": { "assignments": [ { "id": "03a66bf9-1bf4-44c0-92e0-edd45929e467", "name": "code_to_verify_example", "type": "string", "value": "000000" }, { "id": "7bb18b0a-1851-4f27-a91f-5f93b663cfd0", "name": "totp_secret_example", "type": "string", "value": "YOUR_BASE32_SECRET" } ] } }, "typeVersion": 3.4 } ], "active": false, "pinData": {}, "settings": { "executionOrder": "v1" }, "connections": { "EXAMPLE FIELDS": { "main": [ [ { "node": "TOTP VALIDATION", "type": "main", "index": 0 } ] ] }, "TOTP VALIDATION": { "main": [ [ { "node": "IF CODE IS VALID", "type": "main", "index": 0 } ] ] }, "When clicking ‘Test workflow’": { "main": [ [ { "node": "EXAMPLE FIELDS", "type": "main", "index": 0 } ] ] } } }