mirror of
https://github.com/logos-messaging/OpChan.git
synced 2026-01-03 21:33:09 +00:00
add ZKPassport age verification (livestream code)
This commit is contained in:
parent
c91164dbde
commit
fefe7608ad
2121
package-lock.json
generated
2121
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -50,8 +50,11 @@
|
||||
"@reown/appkit-adapter-wagmi": "^1.7.17",
|
||||
"@reown/appkit-wallet-button": "^1.7.17",
|
||||
"@tanstack/react-query": "^5.84.1",
|
||||
"@types/qrcode.react": "^1.0.5",
|
||||
"@waku/sdk": "^0.0.35-67a7287.0",
|
||||
"buffer": "^6.0.3",
|
||||
"@zkpassport/sdk": "^0.8.3",
|
||||
"bitcoinjs-message": "^2.2.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
@ -62,6 +65,7 @@
|
||||
"next-themes": "^0.3.0",
|
||||
"ordiscan": "^1.3.0",
|
||||
"re-resizable": "6.11.2",
|
||||
"qrcode.react": "^4.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
83
src/lib/zkPassport.ts
Normal file
83
src/lib/zkPassport.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { EU_COUNTRIES, ZKPassport } from '@zkpassport/sdk';
|
||||
|
||||
export const verifyAge = async (setProgress: (status:string) => void, setUrl: (url:string) => void): Promise<boolean> => {
|
||||
const zkPassport = new ZKPassport();
|
||||
|
||||
const queryBuilder = await zkPassport.request({
|
||||
name: "OpChan",
|
||||
logo: "https://zkpassport.id/logo.png",
|
||||
purpose: "Prove you are 18+ years old",
|
||||
scope: "adult",
|
||||
});
|
||||
|
||||
const {
|
||||
url,
|
||||
onResult,
|
||||
onGeneratingProof,
|
||||
onError,
|
||||
onProofGenerated,
|
||||
onReject,
|
||||
onRequestReceived
|
||||
} = queryBuilder.gte("age", 18).done();
|
||||
|
||||
setUrl(url);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
console.log("Starting age verification with zkPassport");
|
||||
onRequestReceived(() => {
|
||||
setProgress("Request received, preparing for age verification");
|
||||
console.log("Request received, preparing for age verification");
|
||||
});
|
||||
|
||||
onGeneratingProof(() => {
|
||||
setProgress("Generating cryptographic proof of age");
|
||||
console.log("Generating cryptographic proof of age");
|
||||
});
|
||||
|
||||
onProofGenerated(() => {
|
||||
setProgress("Age proof generated successfully");
|
||||
console.log("Age proof generated successfully");
|
||||
});
|
||||
|
||||
onReject(() => {
|
||||
setProgress("Age verification request was rejected");
|
||||
console.log("Age verification request was rejected by the user");
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
onError((error) => {
|
||||
setProgress(`Age verification error: ${error}`);
|
||||
console.error("Age verification error", error);
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
onResult(({ verified, uniqueIdentifier, result }) => {
|
||||
console.log("Age verification callback", verified, uniqueIdentifier, result);
|
||||
try {
|
||||
console.log("Age verification result", verified, result);
|
||||
if (verified) {
|
||||
const isOver18 = result.age?.gte?.result;
|
||||
setProgress("Age verification completed successfully");
|
||||
resolve(isOver18 || false);
|
||||
console.log("User is 18+ years old", isOver18);
|
||||
} else {
|
||||
setProgress("Age verification failed");
|
||||
resolve(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Age verification result processing error", error);
|
||||
setProgress(`Age verification result processing error: ${error}`);
|
||||
resolve(false);
|
||||
} finally {
|
||||
setUrl('');
|
||||
setProgress('');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Age verification exception", error);
|
||||
setProgress(`Age verification exception: ${error}`);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -7,6 +7,8 @@ import { DelegationFullStatus } from '@/lib/delegation';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { verifyAge } from '@/lib/zkPassport';
|
||||
import { QRCodeCanvas } from 'qrcode.react';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@ -63,6 +65,9 @@ export default function ProfilePage() {
|
||||
EDisplayPreference.WALLET_ADDRESS
|
||||
);
|
||||
const [walletWizardOpen, setWalletWizardOpen] = useState(false);
|
||||
const [url, setUrl] = useState<string>('');
|
||||
const [progress, setProgress] = useState<string>('');
|
||||
const [isVerifying, setIsVerifying] = useState<boolean>(false);
|
||||
|
||||
// Initialize and update local state when user data changes
|
||||
useEffect(() => {
|
||||
@ -587,6 +592,61 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Age Verification Section */}
|
||||
<div className="max-w-md mx-auto mt-8 p-6 bg-cyber-muted/20 border border-cyber-muted/30 rounded-lg">
|
||||
<h2 className="text-xl font-bold text-white mb-4">Age Verification</h2>
|
||||
<p className="text-cyber-neutral mb-4">
|
||||
Verify your age to access restricted content.
|
||||
</p>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
setIsVerifying(true);
|
||||
try {
|
||||
const result = await verifyAge(setProgress, setUrl);
|
||||
console.log('Age verification result:', result);
|
||||
} catch (error) {
|
||||
console.error('Age verification failed:', error);
|
||||
} finally {
|
||||
setIsVerifying(false);
|
||||
}
|
||||
}}
|
||||
disabled={isVerifying}
|
||||
className="w-full bg-cyber-accent hover:bg-cyber-accent/80 text-black font-mono"
|
||||
>
|
||||
{isVerifying ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Verifying...
|
||||
</>
|
||||
) : (
|
||||
'Verify Age'
|
||||
)}
|
||||
</Button>
|
||||
{progress && (
|
||||
<p className="mt-4 text-sm text-cyber-neutral">{progress}</p>
|
||||
)}
|
||||
{url && (
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="text-center">
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-cyber-accent hover:underline font-medium"
|
||||
>
|
||||
Open verification in new tab
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex justify-center p-4 bg-white rounded-lg shadow-lg inline-block">
|
||||
<QRCodeCanvas value={url} size={200} level="H" includeMargin={true} />
|
||||
</div>
|
||||
<p className="text-xs text-cyber-neutral text-center">
|
||||
Scan this QR code to open the verification page on your mobile device
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<footer className="page-footer">
|
||||
<p>OpChan - A decentralized forum built on Waku & Bitcoin Ordinals</p>
|
||||
</footer>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user