first commit

This commit is contained in:
Fabio 2025-12-07 15:17:29 +01:00
commit 2cf2eafe97
11 changed files with 2868 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

107
README.md Normal file
View file

@ -0,0 +1,107 @@
# Webauthn server e client
## Server
porta configurata 3400
vai nel folder server e installa con
npm install
poi avvia il server
node server.js
si avvia su port 3400
nginx é configurato per funzionare con auth.patachina.it
```sh
server {
listen 443 ssl;
server_name auth.patachina.it;
ssl_certificate ssl/live/patachina.it/fullchain.pem;
ssl_certificate_key ssl/live/patachina.it/privkey.pem;
location / {
proxy_pass http://192.168.1.3:3400;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwar>
proxy_set_header X-Forwarded-Proto $scheme;
# Mantieni le connessioni per sessioni
proxy_set_header Connection "";
}
}
```
# Client su nginx
nginx é configurato come my.patachina2.casacam.net
```sh
server {
listen 443 ssl;
server_name my.patachina2.casacam.net;
# Certificati SSL (sostituisci con i tuoi)
ssl_certificate ssl/live/patachina2.casacam.net/fullchai>
ssl_certificate_key ssl/live/patachina2.casacam.net/priv>
# Proxy verso il server statico (npx serve)
location / {
proxy_pass http://192.168.1.3:3000; # npx serve gir>
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwar>
proxy_set_header X-Forwarded-Proto $scheme;
# Mantieni connessioni aperte
proxy_set_header Connection "";
}
# Opzionale: sicurezza base
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
}
```
## Client statico
porta usata 3000
vai su client-static
avvia il server con
npx serve .
l'applicazione é su https://my.patachina2.casacam.net
tutto é stato co figurato per la porta 3000 ma poi avviare anche su altra porta es 3001 ma va cambiato anche nginx
nox serve . -p 3001
## Client con node+vite
vai sul folder client-node-vite
installa
npm install
esegui in modalitá dedug con
npm dev
altrimenti in produzione prima lo buildi e poi lo avvii
npm run build
npm run preview
l'applicazione é su https://my.patachina2.casacam.net visto come abbiamo configurato nginx

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>WebAuthn Client</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="flex flex-col items-center p-6 font-sans bg-gray-50 min-h-screen">
<h1 class="text-3xl font-bold mb-8 text-center">Demo WebAuthn</h1>
<div class="flex flex-col gap-6 w-full max-w-md">
<label for="username" class="font-semibold text-lg">Username:</label>
<input
type="text"
id="username"
value="fabio"
class="border rounded px-4 py-3 w-full text-lg focus:outline-none focus:ring-2 focus:ring-blue>"
/>
<button
id="registerBtn"
class="bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 transition text-lg w-full"
>
Registrati
</button>
<button
id="loginBtn"
class="bg-green-600 text-white py-3 px-4 rounded-lg hover:bg-green-700 transition text-lg w-fu>"
>
Login
</button>
</div>
<script type="module" src="/webauthn-client.js"></script>
</body>
</html>

951
client-node-vite/package-lock.json generated Normal file
View file

@ -0,0 +1,951 @@
{
"name": "webauthn-client",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "webauthn-client",
"version": "1.0.0",
"dependencies": {
"@simplewebauthn/browser": "^13.2.2"
},
"devDependencies": {
"vite": "^5.4.21"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
"integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
"integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@simplewebauthn/browser": {
"version": "13.2.2",
"resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.2.2.tgz",
"integrity": "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==",
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true,
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "4.53.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.53.3",
"@rollup/rollup-android-arm64": "4.53.3",
"@rollup/rollup-darwin-arm64": "4.53.3",
"@rollup/rollup-darwin-x64": "4.53.3",
"@rollup/rollup-freebsd-arm64": "4.53.3",
"@rollup/rollup-freebsd-x64": "4.53.3",
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
"@rollup/rollup-linux-arm64-musl": "4.53.3",
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
"@rollup/rollup-linux-x64-gnu": "4.53.3",
"@rollup/rollup-linux-x64-musl": "4.53.3",
"@rollup/rollup-openharmony-arm64": "4.53.3",
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
"@rollup/rollup-win32-x64-gnu": "4.53.3",
"@rollup/rollup-win32-x64-msvc": "4.53.3",
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "5.4.21",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
"rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^18.0.0 || >=20.0.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
}
}
}

View file

@ -0,0 +1,15 @@
{
"name": "webauthn-client",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.4.21"
},
"dependencies": {
"@simplewebauthn/browser": "^13.2.2"
}
}

View file

@ -0,0 +1,19 @@
import { defineConfig } from 'vite';
export default defineConfig({
server: {
host: '192.168.1.3',
port: 3000,
https: false, // WebAuthn richiede HTTPS (usa certificati validi)
allowedHosts: ['my.patachina2.casacam.net'],
hmr: false,
proxy: {
// opzionale: se vuoi proxare /webauthn verso auth.patachina.it
'/my': {
target: 'https://auth.patachina.it',
changeOrigin: true,
secure: true,
},
},
},
});

View file

@ -0,0 +1,90 @@
import {
startRegistration,
startAuthentication
//} from 'https://cdn.jsdelivr.net/npm/@simplewebauthn/browser/+esm';
} from '@simplewebauthn/browser';
const API_BASE = 'https://auth.patachina.it';
function getUsername() {
return document.getElementById('username').value.trim();
}
async function registerUser() {
try {
const username = getUsername();
const resp = await fetch(`${API_BASE}/my/register-options`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ username: 'fabio' }),
body: JSON.stringify({ username }),
credentials: 'include',
});
const options = await resp.json();
const attResp = await startRegistration(options);
console.log('attResp: ',attResp);
const payload = {
username: 'fabio',
attestationResponse: attResp
};
console.log(payload);
const verif = await fetch(`${API_BASE}/my/register-verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
credentials: 'include',
})
const verification = await verif.json();
console.log('verification: ', verification);
alert(`Registrazione: ${verification.success ? 'OK' : 'Fallita'}`);
} catch (err) {
console.error(err);
alert('Errore nella registrazione');
}
}
async function loginUser() {
try {
const username = getUsername();
const resp = await fetch(`${API_BASE}/my/login-options`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
/* body: JSON.stringify({
username: 'fabio',
}, // tutto loggetto di risposta
), */
body: JSON.stringify({ username }),
credentials: 'include',
});
const options = await resp.json();
if (!resp.ok) {
// Qui uso il campo message inviato dal server
throw new Error(options.message || 'Errore sconosciuto');
}
console.log('options: ',options);
const authResp = await startAuthentication(options);
console.log('authResp: ',authResp);
const verif = await fetch(`${API_BASE}/my/login-verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(
{username: 'fabio',
assertionResponse: authResp}, // tutto loggetto di risposta
),
credentials: 'include',
});
const verification = await verif.json();
console.log('verification: ', verification);
//alert(JSON.stringify(verification));
alert(`Login: ${verification.success ? 'OK' : 'Fallito'}`);
} catch (err) {
console.error(err);
alert(`Login fallito: ${err.message}`);
}
}
document.getElementById('registerBtn').addEventListener('click', registerUser);
document.getElementById('loginBtn').addEventListener('click', loginUser);

130
client-static/index.html Normal file
View file

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>WebAuthn Client</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="flex flex-col items-center p-6 font-sans bg-gray-50 min-h-screen">
<h1 class="text-3xl font-bold mb-8 text-center">Demo WebAuthn</h1>
<div class="flex flex-col gap-6 w-full max-w-md">
<label for="username" class="font-semibold text-lg">Username:</label>
<input
type="text"
id="username"
value="fabio"
class="border rounded px-4 py-3 w-full text-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
id="registerBtn"
class="bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 transition text-lg w-full"
>
Registrati
</button>
<button
id="loginBtn"
class="bg-green-600 text-white py-3 px-4 rounded-lg hover:bg-green-700 transition text-lg w-full"
>
Login
</button>
</div>
<!-- Script come ES Module -->
<script type="module">
import {
startRegistration,
startAuthentication
} from 'https://cdn.jsdelivr.net/npm/@simplewebauthn/browser/+esm';
const API_BASE = 'https://auth.patachina.it';
function getUsername() {
return document.getElementById('username').value.trim();
}
async function registerUser() {
try {
const username = getUsername();
const resp = await fetch(`${API_BASE}/my/register-options`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ username: 'fabio' }),
body: JSON.stringify({ username }),
credentials: 'include',
});
const options = await resp.json();
const attResp = await startRegistration(options);
console.log('attResp: ',attResp);
const payload = {
username: 'fabio',
attestationResponse: attResp
};
console.log(payload);
const verif = await fetch(`${API_BASE}/my/register-verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
credentials: 'include',
})
const verification = await verif.json();
console.log('verification: ', verification);
alert(`Registrazione: ${verification.success ? 'OK' : 'Fallita'}`);
} catch (err) {
console.error(err);
alert('Errore nella registrazione');
}
}
async function loginUser() {
try {
const username = getUsername();
const resp = await fetch(`${API_BASE}/my/login-options`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
/* body: JSON.stringify({
username: 'fabio',
}, // tutto loggetto di risposta
), */
body: JSON.stringify({ username }),
credentials: 'include',
});
const options = await resp.json();
if (!resp.ok) {
// Qui uso il campo message inviato dal server
throw new Error(options.message || 'Errore sconosciuto');
}
console.log('options: ',options);
const authResp = await startAuthentication(options);
console.log('authResp: ',authResp);
const verif = await fetch(`${API_BASE}/my/login-verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(
{username: 'fabio',
assertionResponse: authResp}, // tutto loggetto di risposta
),
credentials: 'include',
});
const verification = await verif.json();
console.log('verification: ', verification);
//alert(JSON.stringify(verification));
alert(`Login: ${verification.success ? 'OK' : 'Fallito'}`);
} catch (err) {
console.error(err);
alert(`Login fallito: ${err.message}`);
}
}
document.getElementById('registerBtn').addEventListener('click', registerUser);
document.getElementById('loginBtn').addEventListener('click', loginUser);
</script>
</body>
</html>

1195
server/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

19
server/package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "webauthn-s",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@simplewebauthn/server": "^13.2.2",
"cors": "^2.8.5",
"express": "^5.1.0",
"express-session": "^1.18.2",
"uuid": "^13.0.0"
}
}

303
server/server.js Normal file
View file

@ -0,0 +1,303 @@
const express = require('express');
const cors = require('cors');
const { v4: uuidv4 } = require('uuid');
const {
generateRegistrationOptions,
verifyRegistrationResponse,
generateAuthenticationOptions,
verifyAuthenticationResponse,
} = require('@simplewebauthn/server');
// CommonJS
const { isoBase64URL } = require('@simplewebauthn/server/helpers');
const session = require('express-session');
const app = express();
app.set('trust proxy', 1); // dietro NGINX/HTTPS
app.use(express.json());
app.use(session({
name: 'sid',
secret: process.env.SESSION_SECRET || 'sono1chiave#moltolunga99esicura',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true, // true in produzione con HTTPS
sameSite: 'none', // 'none' per cross-site; richiede secure:true
maxAge: 24 * 60 * 60 * 1000
}
}));
app.use(cors({
origin: [
'https://app.patachina.it',
'https://my.patachina2.casacam.net',
'http://localhost:5000'
],
credentials: true
}));
const rpID = 'my.patachina2.casacam.net'; // Android emulator localhost
const origin = `https://${rpID}`;
const userDB = {}; // In-memory user store
const appDB = {};
const user1DB = {};
const challregDB = {};
const challlogDB = {};
const uuDB = {};
const uidDB = {};
function isBase64Url(str) {
return typeof str === 'string' && /^[A-Za-z0-9\-_]+$/.test(str);
}
const appMy = {
id: 'my',
appname: 'my',
rpID: 'my.patachina2.casacam.net',
rpName: 'my Local Authn service',
origin: `https://my.patachina2.casacam.net`,
}
appDB['my'] = appMy;
app.post('/:appId/register-options', async (req, res) => {
try {
console.log('start register options');
const appId = req.params.appId;
const { username } = req.body;
if (!appId || !username) {
throw new Error('Missing appId or username');
}
// Genera un nuovo UUID v4
const userIdString = uuidv4();
const userId = Buffer.from(userIdString, 'utf8');
const userId64 = isoBase64URL.fromBuffer(userId);
const key = `${username}:${appId}`;
uuDB[key] = {
id: key,
userId: userId64,
date: new Date(),
};
uidDB[userId64] = {
id: userId64,
app: appId,
devices: [],
};
const options = await generateRegistrationOptions({
rpName: appDB[appId]?.rpName || 'Default RP',
rpID: appDB[appId]?.rpID || 'localhost',
userID: userId,
userName: username,
// authenticatorSelection: { userVerification: 'preferred' }
});
uidDB[userId64].challengereg = options.challenge;
//console.log('options reg: ', options);
//console.log('uidDB[userId64]: ', uidDB[userId64]);
req.session.userID = userId64;
//console.log('session reg opt', req.session);
console.log('end register options user:', username);
res.json(options);
} catch (err) {
console.error('❌ Error in register-options:', err);
// Risposta di errore al client
res.status(500).json({
error: 'Registration options failed',
message: err.message,
});
}
});
app.post('/:appId/register-verify', async (req, res) => {
try {
const { username, attestationResponse } = req.body;
console.log('start session reg ver');
const appId = req.params.appId;
const userId64 = req.session.userID;
if (!userId64 || !uidDB[userId64]) {
throw new Error('User session or uidDB entry not found');
}
const uid = uidDB[userId64];
//console.log('uid.challengereg: ', uid.challengereg);
const verification = await verifyRegistrationResponse({
response: attestationResponse,
expectedChallenge: uid.challengereg,
expectedOrigin: appDB[appId]?.origin,
expectedRPID: appDB[appId]?.rpID,
// requireUserVerification: false,
});
//console.log('verification: ', verification);
delete uidDB[userId64].challengereg;
const success = verification.verified;
if (success) {
uidDB[userId64].devices.push(verification.registrationInfo);
//console.log('uidDB[userId64] dopo ver reg: ', uidDB[userId64]);
console.log('success true');
} else {
console.log('success false');
}
// Gestione distruzione sessione con error handling
req.session.destroy(err => {
if (err) {
console.error('❌ Errore cancellazione sessione:', err);
return res.status(500).json({ success });
}
res.clearCookie('sid').json({ success });
});
} catch (err) {
console.error('❌ Error in register-verify:', err);
res.status(500).json({
success: false,
error: 'Registration verification failed',
message: err.message,
});
}
});
app.post('/:appId/login-options', async (req, res) => {
try {
console.log('start session login opt');
const { username } = req.body;
const appId = req.params.appId;
if (!username || !appId) {
throw new Error('Missing username or appId');
}
const key = `${username}:${appId}`;
if (!uuDB[key]) {
console.log(`Utente ${username} non registrato`);
return res.status(401).json({
success: false,
message: `Utente ${username} non registrato`,
});
}
const userId64 = uuDB[key].userId;
const user = uidDB[userId64];
//console.log('xxx devices:', user);
if (!user || !user.devices || user.devices.length === 0) {
return res.status(404).json({ error: 'User not found or no devices registered' });
}
const all = {
allowCredentials: user.devices.map(dev => ({
id: dev.credential.id, // base64url string
type: 'public-key',
transports: dev.transports || ['internal', 'hybrid'],
})),
userVerification: 'discouraged', // oppure 'preferred' / 'required'
rpID: appDB[appId]?.rpID || 'localhost',
timeout: 60000,
};
const options = await generateAuthenticationOptions(all);
uidDB[userId64].challengelog = options.challenge;
//console.log('uidDB[userId64] ', uidDB[userId64]);
console.log('end session logion options username:',username);
req.session.userID = userId64;
res.json(options);
} catch (err) {
console.error('❌ Error in login-options:', err);
res.status(500).json({
success: false,
error: 'Login options failed',
message: err.message,
});
}
});
app.post('/:appId/login-verify', async (req, res) => {
try {
console.log('start session login verify');
const { username, assertionResponse } = req.body;
const appId = req.params.appId;
const userId64 = req.session.userID;
if (!userId64 || !uidDB[userId64]) {
throw new Error('User session or uidDB entry not found');
}
const user = uidDB[userId64];
if (!user || !user.devices || user.devices.length === 0) {
throw new Error('No devices registered for this user');
}
let verified = false;
let verification;
for (const device of user.devices) {
const verlog = {
response: assertionResponse,
expectedChallenge: user.challengelog,
expectedOrigin: appDB[appId]?.origin,
expectedRPID: appDB[appId]?.rpID,
credential: device.credential,
};
verification = await verifyAuthenticationResponse(verlog);
if (verification.verified) {
verified = true;
// aggiorna il counter del device usato
device.counter = verification.authenticationInfo.newCounter;
break;
}
}
delete uidDB[userId64].challengelog;
// Risposta finale con gestione sessione
req.session.destroy(err => {
if (err) {
console.error('❌ Errore cancellazione sessione:', err);
return res.status(500).json({ success: verified });
}
if (verified) {
//console.log('uidDB[userId64] dopo ver log: ', uidDB[userId64]);
console.log('success true');
return res.clearCookie('sid').json({ success: true });
} else {
console.log('success false');
return res.clearCookie('sid').status(401).json({ success: false });
}
});
} catch (err) {
console.error('❌ Error in login-verify:', err);
res.status(500).json({
success: false,
error: 'Login verification failed',
message: err.message,
});
}
});
app.listen(3400, '192.168.1.3', () => {
console.log('WebAuthn server running on http://192.168.1.3:3400');
});