mirror of
https://github.com/logos-messaging/lab.waku.org.git
synced 2026-01-05 15:23:08 +00:00
chore: add desc, link resources
This commit is contained in:
parent
4f7735e6cb
commit
c6fe4d65e7
@ -43,4 +43,5 @@ If you encounter an "ERC20: insufficient allowance" error, it means the token ap
|
||||
- [ ] update descriptions, and link specs/resources
|
||||
- [ ] footer for discord help
|
||||
- [ ] add info about exporting/using keystore/credential and using with nwaku/nwaku-compose/waku-simulator
|
||||
- [ x ] exporting entire keystore
|
||||
- [ x ] exporting entire keystore
|
||||
- [ ] clean comments
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useKeystore } from '../../../contexts/keystore';
|
||||
import { readKeystoreFromFile, saveKeystoreCredentialToFile } from '../../../utils/keystore';
|
||||
import { readKeystoreFromFile, saveKeystoreCredentialToFile } from '../../../utils/keystore';
|
||||
import { DecryptedCredentials } from '@waku/rln';
|
||||
import { useAppState } from '../../../contexts/AppStateContext';
|
||||
import { TerminalWindow } from '../../ui/terminal-window';
|
||||
import { Button } from '../../ui/button';
|
||||
import { Copy, Eye, Download, Trash2, ArrowDownToLine } from 'lucide-react';
|
||||
import { KeystoreExporter } from '../../KeystoreExporter';
|
||||
import { keystoreManagement, type ContentSegment } from '../../../content/index';
|
||||
|
||||
export function KeystoreManagement() {
|
||||
const {
|
||||
@ -116,7 +117,7 @@ export function KeystoreManagement() {
|
||||
<div className="space-y-6">
|
||||
<TerminalWindow className="w-full">
|
||||
<h2 className="text-lg font-mono font-medium text-primary mb-4 cursor-blink">
|
||||
Keystore Management
|
||||
{keystoreManagement.title}
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-wrap gap-3">
|
||||
@ -127,7 +128,7 @@ export function KeystoreManagement() {
|
||||
>
|
||||
<span className="relative z-10 flex items-center">
|
||||
<ArrowDownToLine className="w-4 h-4 mr-2" />
|
||||
Import Keystore
|
||||
{keystoreManagement.buttons.import}
|
||||
</span>
|
||||
<span className="absolute inset-0 bg-primary/10 transform translate-y-full group-hover:translate-y-0 transition-transform duration-200"></span>
|
||||
</Button>
|
||||
@ -140,15 +141,67 @@ export function KeystoreManagement() {
|
||||
<div className="my-4 p-3 border border-warning-DEFAULT/20 bg-warning-DEFAULT/5 rounded">
|
||||
<p className="text-sm text-warning-DEFAULT font-mono flex items-center">
|
||||
<span className="mr-2">⚠️</span>
|
||||
Please initialize RLN before managing credentials
|
||||
{keystoreManagement.noCredentialsWarning}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* About Section */}
|
||||
<div className="border-t border-terminal-border pt-4 mt-4">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="text-primary font-mono font-medium mr-2">{">"}</span>
|
||||
<h3 className="text-md font-mono font-semibold text-primary">
|
||||
{keystoreManagement.infoHeader}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{keystoreManagement.about.map((paragraph: ContentSegment[], i: number) => (
|
||||
<p key={i} className="text-sm text-foreground mb-2 opacity-90">
|
||||
{paragraph.map((segment: ContentSegment, j: number) => (
|
||||
segment.type === 'link' ? (
|
||||
<a
|
||||
key={j}
|
||||
href={segment.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
{segment.content}
|
||||
</a>
|
||||
) : (
|
||||
<span key={j}>{segment.content}</span>
|
||||
)
|
||||
))}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Resources Section */}
|
||||
<div className="border-t border-terminal-border pt-4">
|
||||
<h3 className="text-md font-mono font-semibold text-primary mb-3">
|
||||
{keystoreManagement.resources.title}
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{keystoreManagement.resources.links.map((link: { name: string; url: string }, i: number) => (
|
||||
<a
|
||||
key={i}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline text-sm"
|
||||
>
|
||||
{link.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stored Credentials */}
|
||||
<div className="border-t border-terminal-border pt-6">
|
||||
<h3 className="text-sm font-mono font-medium text-muted-foreground mb-4">
|
||||
Stored Credentials
|
||||
{keystoreManagement.storedCredentialsTitle}
|
||||
</h3>
|
||||
|
||||
{hasStoredCredentials ? (
|
||||
@ -189,7 +242,7 @@ export function KeystoreManagement() {
|
||||
className="text-accent hover:text-accent hover:border-accent flex items-center gap-1 py-1"
|
||||
>
|
||||
<Eye className="w-3 h-3" />
|
||||
<span>View</span>
|
||||
<span>{keystoreManagement.buttons.view}</span>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@ -10,6 +10,7 @@ import { RLNInitButton } from '../../RLNinitButton';
|
||||
import { TerminalWindow } from '../../ui/terminal-window';
|
||||
import { Slider } from '../../ui/slider';
|
||||
import { Button } from '../../ui/button';
|
||||
import { membershipRegistration, type ContentSegment } from '../../../content/index';
|
||||
|
||||
export function MembershipRegistration() {
|
||||
const { setGlobalError } = useAppState();
|
||||
@ -101,7 +102,7 @@ export function MembershipRegistration() {
|
||||
<div className="space-y-6 max-w-full">
|
||||
<TerminalWindow className="w-full">
|
||||
<h2 className="text-lg font-mono font-medium text-primary mb-4 cursor-blink">
|
||||
RLN Membership Registration
|
||||
{membershipRegistration.title}
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
<div className="border-b border-terminal-border pb-6">
|
||||
@ -113,35 +114,43 @@ export function MembershipRegistration() {
|
||||
<div className="mb-4 p-3 border border-destructive/20 bg-destructive/5 rounded">
|
||||
<p className="text-sm text-destructive font-mono flex items-center">
|
||||
<span className="mr-2">⚠️</span>
|
||||
<span>You are not connected to Linea Sepolia network. Please switch networks to register.</span>
|
||||
<span>{membershipRegistration.networkWarning}</span>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Informational Box - Now part of main terminal */}
|
||||
{/* Informational Box */}
|
||||
<div className="border-t border-terminal-border pt-4 mt-4">
|
||||
<div className="flex items-center mb-3">
|
||||
<span className="text-primary font-mono font-medium mr-2">{">"}</span>
|
||||
<h3 className="text-md font-mono font-semibold text-primary">
|
||||
RLN Membership Info
|
||||
{membershipRegistration.infoHeader}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-md font-mono font-semibold text-primary cursor-blink">
|
||||
About RLN Membership on Linea Sepolia
|
||||
{membershipRegistration.aboutTitle}
|
||||
</h4>
|
||||
<p className="text-sm text-foreground mb-2 opacity-90">
|
||||
RLN (Rate Limiting Nullifier) membership allows you to participate in Waku RLN Relay with rate limiting protection,
|
||||
without exposing your private keys on your node.
|
||||
</p>
|
||||
<p className="text-sm text-foreground mb-2 opacity-90">
|
||||
This application is configured to use the <span className="text-primary">Linea Sepolia</span> testnet for RLN registrations.
|
||||
</p>
|
||||
<p className="text-sm text-foreground opacity-90">
|
||||
When you register, your wallet will sign a message that will be used to generate a cryptographic identity
|
||||
for your membership. This allows your node to prove it has permission to send messages without revealing your identity.
|
||||
</p>
|
||||
{membershipRegistration.about.map((paragraph: ContentSegment[], i: number) => (
|
||||
<p key={i} className="text-sm text-foreground mb-2 opacity-90">
|
||||
{paragraph.map((segment: ContentSegment, j: number) => (
|
||||
segment.type === 'link' ? (
|
||||
<a
|
||||
key={j}
|
||||
href={segment.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
{segment.content}
|
||||
</a>
|
||||
) : (
|
||||
<span key={j}>{segment.content}</span>
|
||||
)
|
||||
))}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -153,12 +162,12 @@ export function MembershipRegistration() {
|
||||
{!isConnected ? (
|
||||
<div className="text-warning-DEFAULT font-mono text-sm mt-4 flex items-center">
|
||||
<span className="mr-2">ℹ️</span>
|
||||
Please connect your wallet to register a membership
|
||||
{membershipRegistration.connectWalletPrompt}
|
||||
</div>
|
||||
) : !isInitialized || !isStarted ? (
|
||||
<div className="text-warning-DEFAULT font-mono text-sm mt-4 flex items-center">
|
||||
<span className="mr-2">ℹ️</span>
|
||||
Please initialize RLN before registering a membership
|
||||
{membershipRegistration.initializePrompt}
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-4 mt-4">
|
||||
@ -167,7 +176,7 @@ export function MembershipRegistration() {
|
||||
htmlFor="rateLimit"
|
||||
className="block text-sm font-mono text-muted-foreground mb-2"
|
||||
>
|
||||
Rate Limit (messages per epoch)
|
||||
{membershipRegistration.form.rateLimitLabel}
|
||||
</label>
|
||||
<div className="flex items-center space-x-4 py-2">
|
||||
<Slider
|
||||
@ -197,24 +206,25 @@ export function MembershipRegistration() {
|
||||
htmlFor="saveToKeystore"
|
||||
className="ml-2 text-sm font-mono text-foreground"
|
||||
>
|
||||
Save credentials to keystore
|
||||
{membershipRegistration.form.saveToKeystoreLabel}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{saveToKeystore && (
|
||||
<div>
|
||||
<label
|
||||
htmlFor="keystorePassword"
|
||||
className="block text-sm font-mono text-muted-foreground mb-1"
|
||||
className="block text-sm font-mono text-muted-foreground mb-2"
|
||||
>
|
||||
Keystore Password (min 8 characters)
|
||||
{membershipRegistration.form.passwordLabel}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="keystorePassword"
|
||||
value={keystorePassword}
|
||||
onChange={(e) => setKeystorePassword(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-terminal-border rounded-md bg-terminal-background text-foreground font-mono focus:ring-1 focus:ring-primary focus:border-primary text-sm"
|
||||
placeholder="Enter password to encrypt credentials"
|
||||
placeholder={membershipRegistration.form.passwordPlaceholder}
|
||||
className="w-full px-3 py-2 bg-terminal-background border border-terminal-border rounded-md text-sm font-mono focus:outline-none focus:ring-2 focus:ring-primary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -222,11 +232,10 @@ export function MembershipRegistration() {
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isRegistering || !isLineaSepolia || (saveToKeystore && !keystorePassword)}
|
||||
variant={isRegistering ? "outline" : "default"}
|
||||
disabled={isRegistering}
|
||||
className="w-full"
|
||||
>
|
||||
{isRegistering ? 'Registering...' : 'Register Membership'}
|
||||
{isRegistering ? membershipRegistration.form.registeringButton : membershipRegistration.form.registerButton}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
104
examples/keystore-management/src/content/index.ts
Normal file
104
examples/keystore-management/src/content/index.ts
Normal file
@ -0,0 +1,104 @@
|
||||
// Types for content structure
|
||||
type Link = {
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type ContentSegment = {
|
||||
type: 'text' | 'link';
|
||||
content: string;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
export type Paragraph = ContentSegment[];
|
||||
|
||||
// Content for RLN Membership Registration
|
||||
export const membershipRegistration = {
|
||||
title: "RLN Membership Registration",
|
||||
aboutTitle: "About RLN Membership on Linea Sepolia",
|
||||
about: [
|
||||
[
|
||||
{ type: 'text', content: 'RLN (' },
|
||||
{ type: 'link', content: 'Rate Limiting Nullifier', url: 'https://github.com/Rate-Limiting-Nullifier' },
|
||||
{ type: 'text', content: ') membership allows you to participate in ' },
|
||||
{ type: 'link', content: 'Waku RLN Relay', url: 'https://blog.waku.org/explanation-series-rln-relay/' },
|
||||
{ type: 'text', content: ' with rate limiting protection, without exposing your private keys on your node.' }
|
||||
],
|
||||
[
|
||||
{ type: 'text', content: 'This application is configured to use the ' },
|
||||
{ type: 'link', content: 'Linea Sepolia', url: 'https://sepolia.lineascan.build/address/0xb9cd878c90e49f797b4431fbf4fb333108cb90e6' },
|
||||
{ type: 'text', content: ' testnet for RLN registrations.' }
|
||||
],
|
||||
[
|
||||
{ type: 'text', content: 'When you register, your wallet will sign a message that will be used to generate a ' },
|
||||
{ type: 'link', content: 'cryptographic identity', url: 'https://github.com/waku-org/specs/blob/master/standards/application/rln-keystore.md' },
|
||||
{ type: 'text', content: ' for your membership. This allows your node to prove it has permission to send messages without revealing your identity.' }
|
||||
]
|
||||
] as Paragraph[],
|
||||
infoHeader: "RLN Membership Info",
|
||||
connectWalletPrompt: "Please connect your wallet to register a membership",
|
||||
initializePrompt: "Please initialize RLN before registering a membership",
|
||||
networkWarning: "You are not connected to Linea Sepolia network. Please switch networks to register.",
|
||||
|
||||
form: {
|
||||
rateLimitLabel: "Rate Limit (messages per epoch)",
|
||||
saveToKeystoreLabel: "Save credentials to keystore",
|
||||
passwordLabel: "Keystore Password (min 8 characters)",
|
||||
passwordPlaceholder: "Enter password to encrypt credentials",
|
||||
registerButton: "Register Membership",
|
||||
registeringButton: "Registering..."
|
||||
}
|
||||
};
|
||||
|
||||
// Content for Keystore Management
|
||||
export const keystoreManagement = {
|
||||
title: "Keystore Management",
|
||||
buttons: {
|
||||
import: "Import Keystore",
|
||||
export: "Export Keystore",
|
||||
view: "View",
|
||||
decrypt: "Decrypt",
|
||||
decrypting: "Decrypting...",
|
||||
remove: "Remove"
|
||||
},
|
||||
|
||||
about: [
|
||||
[
|
||||
{ type: 'text', content: 'Keystore management allows you to securely store, import, export and manage your ' },
|
||||
{ type: 'link', content: 'RLN membership credentials', url: 'https://github.com/waku-org/specs/blob/master/standards/application/rln-keystore.md' },
|
||||
{ type: 'text', content: '.' }
|
||||
],
|
||||
[
|
||||
{ type: 'text', content: 'Credentials are encrypted with your password and can be used across different devices or applications. Learn more about ' },
|
||||
{ type: 'link', content: 'keystore security', url: 'https://github.com/waku-org/specs/blob/master/standards/application/rln-keystore.md#security-considerations' },
|
||||
{ type: 'text', content: '.' }
|
||||
],
|
||||
[
|
||||
{ type: 'text', content: 'You can export your credentials as a file and import them on another device to use the same membership.' }
|
||||
]
|
||||
] as Paragraph[],
|
||||
|
||||
infoHeader: "About Keystore Management",
|
||||
noCredentialsWarning: "Please initialize RLN before managing credentials",
|
||||
storedCredentialsTitle: "Stored Credentials",
|
||||
passwordPlaceholder: "Enter credential password",
|
||||
credentialDetailsTitle: "Credential Details",
|
||||
|
||||
resources: {
|
||||
title: "Resources",
|
||||
links: [
|
||||
{
|
||||
name: "RLN Specs",
|
||||
url: "https://specs.status.im/spec/waku/rln-v1"
|
||||
},
|
||||
{
|
||||
name: "Waku GitHub",
|
||||
url: "https://github.com/waku-org/waku-rln-contract"
|
||||
},
|
||||
{
|
||||
name: "Keystore Documentation",
|
||||
url: "https://github.com/waku-org/specs/blob/master/standards/application/rln-keystore.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user