
Security News
Open Source Maintainers Feeling the Weight of the EU’s Cyber Resilience Act
The EU Cyber Resilience Act is prompting compliance requests that open source maintainers may not be obligated or equipped to handle.
@usewayn/server
Advanced tools
A proof-of-work challenge system for rate limiting and bot protection. This SDK provides a server-side implementation for creating cryptographic challenges that clients must solve to prove computational work.
npm install @usewayn/server # NodeJS
bun install @usewayn/server # Bun
import Wayn from '@usewayn/server';
// Create a new Wayn instance
const wayn = new Wayn({
stateless: true, // Optional: enables JWT authentication (default: true)
jwtSecret: 'ReallySecretKey29!', // Optional: defaults to random bytes
});
// Create a challenge for the client
const challenge = wayn.createChallenge({
challengeCount: 5, // Number of challenges
challengeSize: 32, // Size of each challenge
challengeDifficulty: 5, // Difficulty level
expiresMs: 300000, // Expiration time (5 minutes)
});
// Validate a solution from the client
const result = await wayn.redeemChallenge({
token: challenge.token,
solutions: clientSolutions, // Array of [salt, target, nonce] tuples
});
if (result.success) {
// Challenge solved successfully
const validationResult = await wayn.validateToken(result.token);
console.log('Token is valid:', validationResult.success);
}
new Wayn(config?: Partial<WaynConfig>)
Creates a new Wayn instance with optional configuration.
Parameters:
config.jwtSecret
(string): Secret key for JWT token signing. Defaults to random bytes.config.stateless
(boolean): Whether to use JWT tokens (true) or in-memory tokens (false). Default: true.config.state
(ChallengeState): Initial state for challenges and tokens. Only used when stateless is false.createChallenge(config?: ChallengeConfig)
Creates a new proof-of-work challenge for clients to solve.
Parameters:
config.challengeCount
(number): Number of individual challenges. Default: 50config.challengeSize
(number): Size of each challenge string in characters. Default: 32config.challengeDifficulty
(number): Number of leading zeros required in hash. Default: 4config.expiresMs
(number): Challenge expiration time in milliseconds. Default: 600000 (10 minutes)config.store
(boolean): Whether to store the challenge server-side. Default: trueReturns:
{
challenge: Array<[string, string]>, // Array of [salt, target] tuples
token?: string, // Challenge token (if stored)
expires: number // Expiration timestamp
}
Example:
const challenge = wayn.createChallenge({
challengeCount: 5,
challengeDifficulty: 3,
expiresMs: 300000, // 5 minutes
});
// Send challenge.challenge to client
// Store challenge.token for validation
redeemChallenge(solution: Solution)
Validates a client's solution to a previously created challenge.
Parameters:
{
token: string, // Challenge token
solutions: Array<[string, string, number]> // Array of [salt, target, nonce] tuples
}
Returns:
{
success: boolean,
message?: string, // Error message if success is false
token?: string, // Verification token if success is true
expires?: number // Token expiration timestamp
}
Example:
const result = await wayn.redeemChallenge({
token: challengeToken,
solutions: [
['salt1', 'target1', 12345],
['salt2', 'target2', 67890],
// ... more solutions
]
});
if (result.success) {
// Store result.token for future validations
console.log('Challenge solved! Token expires at:', new Date(result.expires));
} else {
console.error('Challenge failed:', result.message);
}
validateToken(token: string, config?: TokenConfig)
Validates a previously issued verification token.
Parameters:
token
(string): The verification token to validateconfig.keepToken
(boolean): Whether to keep the token valid after validation (only for non-stateless mode). Default: falseReturns:
{
success: boolean,
payload?: JWTPayload // JWT payload (only in stateless mode)
}
Example:
const validation = await wayn.validateToken(userToken);
if (validation.success) {
if (validation.payload) {
// Stateless mode - JWT token
console.log('User ID:', validation.payload.id);
console.log('Challenge solved at:', new Date(validation.payload.solvedAt * 1000));
console.log('Average solution time:', validation.payload.avgSolutionTime, 'ms');
}
// Allow user to proceed
} else {
// Token is invalid or expired
}
Option | Type | Default | Description |
---|---|---|---|
challengeCount | number | 50 | Number of proof-of-work challenges to generate |
challengeSize | number | 32 | Length of each challenge salt in characters |
challengeDifficulty | number | 4 | Number of leading zeros required in SHA-256 hash |
expiresMs | number | 600000 | Challenge expiration time in milliseconds (10 min) |
store | boolean | true | Whether to store challenge server-side for validation |
Option | Type | Default | Description |
---|---|---|---|
keepToken | boolean | false | Keep token valid after validation (non-stateless only) |
const wayn = new Wayn();
// Create challenge with higher difficulty for rate limiting
const challenge = wayn.createChallenge({
challengeCount: 20,
challengeDifficulty: 5, // Requires more computation
expiresMs: 300000, // 5 minutes
});
// Client must solve challenge before making API calls
const wayn = new Wayn();
// Lighter challenge for bot protection
const challenge = wayn.createChallenge({
challengeCount: 3,
challengeDifficulty: 3,
expiresMs: 120000, // 2 minutes
});
// Validate before allowing form submissions
Stateless Mode (Recommended):
const wayn = new Wayn({ stateless: true });
Stateful Mode:
const wayn = new Wayn({ stateless: false });
The SDK is written in TypeScript and includes full type definitions:
import Wayn, {
WaynConfig,
ChallengeConfig,
Solution,
JWTPayload
} from '@usewayn/server';
This project was created using bun init
in bun v1.2.0. Bun is a fast all-in-one JavaScript runtime.
FAQs
Server-side actions handler for Wayn PoW CAPTCHA.
We found that @usewayn/server demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The EU Cyber Resilience Act is prompting compliance requests that open source maintainers may not be obligated or equipped to handle.
Security News
Crates.io adds Trusted Publishing support, enabling secure GitHub Actions-based crate releases without long-lived API tokens.
Research
/Security News
Undocumented protestware found in 28 npm packages disrupts UI for Russian-language users visiting Russian and Belarusian domains.