-
Notifications
You must be signed in to change notification settings - Fork 0
667 add passkey examaple #718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
Closes #667
PR SummaryCreated a comprehensive Flow passkey wallet example application demonstrating WebAuthn integration with Flow blockchain. The app includes a complete Next.js setup with authentication, transaction signing, and wallet management using passkeys instead of traditional seed phrases. Features include passkey creation/login, Flow account management, transaction signing with WebAuthn, and a modern UI built with Tamagui components. Changes
autogenerated by presubmit.ai |
Dependency ReviewThe following issues were found:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚨 Pull request needs attention.
Review Summary
Commits Considered (5)
- 4abcf41: feat: fix authn and authz styling
Closes #667
- cc92070: chore: clean up code
Closes #667
- 2044b99: feat: update passkey ui style
Closes #667
- 31229d5: feat: update passkey styles
Closes #667
- 539c14a: feat: add passkey login page
Closes #667
Files Processed (30)
- .claude/settings.local.json (1 hunk)
- .gitignore (1 hunk)
- apps/passkeys/.env.example (1 hunk)
- apps/passkeys/.eslintrc.cjs (1 hunk)
- apps/passkeys/.prettierrc (1 hunk)
- apps/passkeys/README.md (1 hunk)
- apps/passkeys/next-env.d.ts (1 hunk)
- apps/passkeys/next.config.js (1 hunk)
- apps/passkeys/package.json (1 hunk)
- apps/passkeys/public/favicon.ico (1 hunk)
- apps/passkeys/public/img/landing.jpg (0 hunks)
- apps/passkeys/src/components/Passkey/CTASection.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/FeatureCards.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/StickyHeader.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/WalletFooter.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/WalletHero.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/WalletPreview.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/auth-container.tsx (1 hunk)
- apps/passkeys/src/components/Passkey/passkey-select.tsx (1 hunk)
- apps/passkeys/src/components/passkey-login.tsx (1 hunk)
- apps/passkeys/src/components/passkey-setup.tsx (1 hunk)
- apps/passkeys/src/components/passkey-sign-container.tsx (1 hunk)
- apps/passkeys/src/components/wallet-dashboard.tsx (1 hunk)
- apps/passkeys/src/pages/_app.tsx (1 hunk)
- apps/passkeys/src/pages/_document.tsx (1 hunk)
- apps/passkeys/src/pages/api/create-address.ts (1 hunk)
- apps/passkeys/src/pages/api/find-address.ts (1 hunk)
- apps/passkeys/src/pages/authn.tsx (1 hunk)
- apps/passkeys/src/pages/authz.tsx (1 hunk)
- apps/passkeys/src/pages/index.tsx (1 hunk)
Actionable Comments (3)
-
apps/passkeys/src/pages/api/create-address.ts [32-42]
security: "Missing environment variable validation"
-
apps/passkeys/src/pages/api/create-address.ts [16-20]
security: "Missing input validation for public key"
-
apps/passkeys/src/pages/api/find-address.ts [10-14]
security: "Missing input validation for public key parameter"
Skipped Comments (7)
-
apps/passkeys/.env.example [8-8]
best practice: "Missing newline at end of file"
-
apps/passkeys/.eslintrc.cjs [35-35]
best practice: "Missing newline at end of file"
-
apps/passkeys/.prettierrc [14-14]
best practice: "Missing newline at end of file"
-
apps/passkeys/public/favicon.ico [2-2]
best practice: "Missing newline at end of file"
-
apps/passkeys/src/components/passkey-login.tsx [41-41]
security: "Potential exposure of sensitive key information"
-
apps/passkeys/src/components/passkey-setup.tsx [47-47]
security: "Potential exposure of sensitive key information"
-
apps/passkeys/src/pages/index.tsx [347-349]
possible issue: "Hardcoded newline character in text"
| headers: { | ||
| Authorization: process.env.LILICO_API_KEY || '', | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({ | ||
| publicKey, | ||
| weight, | ||
| hashAlgorithm, | ||
| signatureAlgorithm, | ||
| }), | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API endpoint uses process.env.LILICO_API_KEY without proper validation. If the environment variable is undefined or empty, it will send an empty Authorization header, which could cause authentication failures or expose the endpoint to unauthorized access.
| } = req.body; | ||
|
|
||
| if (!publicKey) { | ||
| return res.status(400).json({ error: 'Public key is required' }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API endpoint accepts user input for publicKey without proper validation. This could potentially lead to injection attacks or malformed requests to the external API.
| const { publicKey } = req.query; | ||
|
|
||
| if (!publicKey || typeof publicKey !== 'string') { | ||
| return res.status(400).json({ error: 'Public key is required' }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API endpoint accepts user input for publicKey from query parameters without proper validation. This could potentially lead to injection attacks or malformed requests to the external API.
| ); | ||
| } | ||
|
|
||
| if (!signerAddress) { |
Check failure
Code scanning / CodeQL
User-controlled bypass of security check High
action
user-provided value
| useEffect(() => { | ||
| if (typeof window === 'undefined') return; | ||
|
|
||
| const handleMessage = (event: MessageEvent) => { |
Check warning
Code scanning / CodeQL
Missing origin verification in `postMessage` handler Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix the problem, we need to ensure that the message handler validates the origin of the incoming message before processing it. Specifically:
- Only messages sent from trusted origins (e.g., the expected wallet or dApp origin) should be processed; messages from any other origin must be ignored.
- The safest option is to define a constant or configuration (e.g.,
ALLOWED_ORIGIN) representing the allowed origin(s), and checkevent.originagainst this before handling any message. - Modify the handler function in
apps/passkeys/src/pages/authn.tsx(lines 111-143) to insert this origin check immediately at the top of the function. - You may add a definition for the allowed origin(s), either as a constant above the
useEffect, or inline (if a single origin is expected).
No new imports are required; event.origin is a platform property.
-
Copy modified lines R108-R111 -
Copy modified lines R116-R120
| @@ -105,10 +105,19 @@ | ||
| const [appName, setAppName] = useState<string>('Flow dApp'); | ||
| const [appUrl, setAppUrl] = useState<string | undefined>(); | ||
|
|
||
| // Only accept messages from the allowed origin. | ||
| // Replace this with the trusted dApp/wallet origin as appropriate. | ||
| const ALLOWED_ORIGIN = 'https://www.example.com'; | ||
|
|
||
| useEffect(() => { | ||
| if (typeof window === 'undefined') return; | ||
|
|
||
| const handleMessage = (event: MessageEvent) => { | ||
| if (event.origin !== ALLOWED_ORIGIN) { | ||
| // Optionally log rejected messages for debugging: | ||
| logger.warn(`Rejected message from untrusted origin: ${event.origin}`); | ||
| return; | ||
| } | ||
| const { data } = event; | ||
| if (!data || typeof data !== 'object') { | ||
| return; |
| useEffect(() => { | ||
| if (typeof window === 'undefined') return; | ||
|
|
||
| const handleMessage = (event: MessageEvent) => { |
Check warning
Code scanning / CodeQL
Missing origin verification in `postMessage` handler Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix this vulnerability, you should verify the origin of incoming messages to ensure they originate from a trusted source before acting on their data payload. This check should be performed in the handleMessage function, where you should compare event.origin to the expected trusted origin (such as the main app domain, e.g., 'https://app.example.com', or using an environment variable for flexibility). Place this check near the top of the function, immediately after extracting event. Only process further if the check passes; otherwise, ignore the message. Since the code does not define a list of trusted origins, and only edits within this file are allowed, define a constant within this file (e.g., const TRUSTED_ORIGIN = ...) above the hook/component, and use that for comparison.
Insert the origin check just after line 89 (const { data } = event;), with comments explaining its purpose. If the origin does not match, immediately return. Place the trusted origin string as an explicit constant, e.g., 'https://app.example.com', or as close as possible to the real domain. If environment variables are used to set the origin, you can use them, but only if their access is shown in the current code snippet.
-
Copy modified lines R75-R77 -
Copy modified lines R93-R97
| @@ -72,6 +72,9 @@ | ||
| : 'testnet'; | ||
|
|
||
| export default function AuthzPage() { | ||
| // Define the trusted origin for postMessage verification | ||
| const TRUSTED_ORIGIN = 'https://app.example.com'; // <-- CHANGE to your actual origin | ||
|
|
||
| const [signable, setSignable] = useState<FlowSignable | null>(null); | ||
| const [credentials, setCredentials] = useState<CredentialItem[]>([]); | ||
| const [selectedId, setSelectedId] = useState<string | null>(null); | ||
| @@ -87,6 +90,11 @@ | ||
|
|
||
| const handleMessage = (event: MessageEvent) => { | ||
| const { data } = event; | ||
| // Security: verify event.origin is trusted before handling message | ||
| if (event.origin !== TRUSTED_ORIGIN) { | ||
| logger.warn(`Untrusted message origin: ${event.origin}`); | ||
| return; | ||
| } | ||
| if (!data || typeof data !== 'object') { | ||
| return; | ||
| } |
🔗 Related Issues
Closes #667
Linked automatically from the branch name. If incorrect, edit:
📝 Description
📸 Screenshots/Videos