mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
docs: tsx,powertransfertab,packages (3 files)
This commit is contained in:
@@ -213,14 +213,103 @@ private handleMessage(data: string): void {
|
||||
- Could modify Object prototype affecting all objects in process
|
||||
- Pattern: CVE-2019-10744 (lodash prototype pollution)
|
||||
|
||||
**Recommendation**:
|
||||
**🏰 Fort Knox Remediation**:
|
||||
```typescript
|
||||
import { safeJsonParse } from './security-utils'
|
||||
/**
|
||||
* Fort Knox JSON Parser
|
||||
* - Blocks prototype pollution
|
||||
* - Enforces depth limits
|
||||
* - Validates structure against schema
|
||||
* - Sanitizes string content
|
||||
*/
|
||||
class SecureJsonParser {
|
||||
private static readonly MAX_DEPTH = 10
|
||||
private static readonly MAX_STRING_LENGTH = 1_000_000 // 1MB
|
||||
private static readonly MAX_ARRAY_LENGTH = 10_000
|
||||
private static readonly MAX_OBJECT_KEYS = 1000
|
||||
|
||||
private static readonly FORBIDDEN_KEYS = new Set([
|
||||
'__proto__',
|
||||
'constructor',
|
||||
'prototype',
|
||||
'__defineGetter__',
|
||||
'__defineSetter__',
|
||||
'__lookupGetter__',
|
||||
'__lookupSetter__',
|
||||
])
|
||||
|
||||
static parse<T>(json: string, schema?: ZodSchema<T>): T {
|
||||
// 1. Length check
|
||||
if (json.length > this.MAX_STRING_LENGTH) {
|
||||
throw DBALError.validationError('JSON input too large', [
|
||||
{ field: 'json', error: `Max ${this.MAX_STRING_LENGTH} bytes` }
|
||||
])
|
||||
}
|
||||
|
||||
// 2. Parse with reviver for prototype protection
|
||||
let depth = 0
|
||||
const parsed = JSON.parse(json, (key, value) => {
|
||||
// Block dangerous keys
|
||||
if (this.FORBIDDEN_KEYS.has(key)) {
|
||||
throw DBALError.maliciousCode(`Forbidden key in JSON: ${key}`)
|
||||
}
|
||||
|
||||
// Track and limit depth
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
depth++
|
||||
if (depth > this.MAX_DEPTH) {
|
||||
throw DBALError.validationError('JSON nesting too deep')
|
||||
}
|
||||
|
||||
// Limit object keys
|
||||
if (!Array.isArray(value) && Object.keys(value).length > this.MAX_OBJECT_KEYS) {
|
||||
throw DBALError.validationError('Too many object keys')
|
||||
}
|
||||
|
||||
// Limit array length
|
||||
if (Array.isArray(value) && value.length > this.MAX_ARRAY_LENGTH) {
|
||||
throw DBALError.validationError('Array too large')
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
})
|
||||
|
||||
// 3. Validate against schema if provided
|
||||
if (schema) {
|
||||
const result = schema.safeParse(parsed)
|
||||
if (!result.success) {
|
||||
throw DBALError.validationError('Schema validation failed',
|
||||
result.error.issues.map(i => ({ field: i.path.join('.'), error: i.message }))
|
||||
)
|
||||
}
|
||||
return result.data
|
||||
}
|
||||
|
||||
// 4. Deep freeze to prevent mutation
|
||||
return this.deepFreeze(parsed)
|
||||
}
|
||||
|
||||
private static deepFreeze<T>(obj: T): T {
|
||||
if (obj === null || typeof obj !== 'object') return obj
|
||||
|
||||
Object.freeze(obj)
|
||||
Object.getOwnPropertyNames(obj).forEach(prop => {
|
||||
const value = (obj as any)[prop]
|
||||
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
||||
this.deepFreeze(value)
|
||||
}
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
const response = safeJsonParse(data, {
|
||||
protoAction: 'remove',
|
||||
constructorAction: 'remove'
|
||||
})
|
||||
// Usage in WebSocket bridge
|
||||
private handleMessage(data: string): void {
|
||||
const response = SecureJsonParser.parse(data, RPCResponseSchema)
|
||||
// response is now validated, frozen, and safe
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -31,11 +31,14 @@ const renderComponent = (overrides?: { onInitiate?: () => void }) => {
|
||||
return { onInitiateTransfer }
|
||||
}
|
||||
|
||||
const mockFetch = (payload: any) =>
|
||||
vi.stubGlobal('fetch', async () => ({
|
||||
const mockFetch = (payload: any) => {
|
||||
const fetchMock = vi.fn(async () => ({
|
||||
ok: true,
|
||||
json: async () => payload,
|
||||
}))
|
||||
vi.stubGlobal('fetch', fetchMock)
|
||||
return fetchMock
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
@@ -71,7 +74,7 @@ describe('PowerTransferTab', () => {
|
||||
|
||||
const { onInitiateTransfer } = renderComponent()
|
||||
|
||||
await waitFor(() => expect(screen.getByText(/Select User/i)).toBeInTheDocument())
|
||||
await screen.findByText(/Select User/i)
|
||||
|
||||
fireEvent.click(screen.getByText('target-god'))
|
||||
const actionButton = screen.getByRole('button', { name: /Initiate Power Transfer/i })
|
||||
|
||||
@@ -10,6 +10,26 @@
|
||||
"id": "cat_growth",
|
||||
"name": "Growth Ops",
|
||||
"description": "Retention, onboarding, and community tactics"
|
||||
},
|
||||
{
|
||||
"id": "cat_design",
|
||||
"name": "Design Systems",
|
||||
"description": "Tokens, theming, and UI governance"
|
||||
},
|
||||
{
|
||||
"id": "cat_ai",
|
||||
"name": "AI Tooling",
|
||||
"description": "Prompt playbooks, evals, and guardrails"
|
||||
},
|
||||
{
|
||||
"id": "cat_ops",
|
||||
"name": "Community Ops",
|
||||
"description": "Moderation workflows and engagement rituals"
|
||||
},
|
||||
{
|
||||
"id": "cat_hiring",
|
||||
"name": "Hiring & Ops",
|
||||
"description": "Team growth, planning, and operating cadence"
|
||||
}
|
||||
],
|
||||
"threads": [
|
||||
@@ -26,6 +46,48 @@
|
||||
"categoryId": "cat_launch",
|
||||
"replyCount": 18,
|
||||
"likeCount": 64
|
||||
},
|
||||
{
|
||||
"id": "thread_3",
|
||||
"title": "Building a tokenized design system",
|
||||
"categoryId": "cat_design",
|
||||
"replyCount": 27,
|
||||
"likeCount": 88
|
||||
},
|
||||
{
|
||||
"id": "thread_4",
|
||||
"title": "How to measure community health",
|
||||
"categoryId": "cat_ops",
|
||||
"replyCount": 33,
|
||||
"likeCount": 96
|
||||
},
|
||||
{
|
||||
"id": "thread_5",
|
||||
"title": "Prompt playbooks for onboarding",
|
||||
"categoryId": "cat_ai",
|
||||
"replyCount": 21,
|
||||
"likeCount": 54
|
||||
},
|
||||
{
|
||||
"id": "thread_6",
|
||||
"title": "Moderation handoff checklists",
|
||||
"categoryId": "cat_ops",
|
||||
"replyCount": 19,
|
||||
"likeCount": 41
|
||||
},
|
||||
{
|
||||
"id": "thread_7",
|
||||
"title": "Hiring your first community lead",
|
||||
"categoryId": "cat_hiring",
|
||||
"replyCount": 15,
|
||||
"likeCount": 33
|
||||
},
|
||||
{
|
||||
"id": "thread_8",
|
||||
"title": "Feature flag cadence for launches",
|
||||
"categoryId": "cat_launch",
|
||||
"replyCount": 12,
|
||||
"likeCount": 29
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user