Skip to content

Commit

Permalink
Merge pull request #3 from viapip/master
Browse files Browse the repository at this point in the history
proxy, mongodb
  • Loading branch information
semyenov authored Mar 14, 2024
2 parents b097174 + 3fe51bc commit e185595
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 77 deletions.
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"yatki.vscode-surround",
"yoavbls.pretty-ts-errors",
"Yseop.vscode-yseopml",
"zardoy.ts-essential-plugins"
"zardoy.ts-essential-plugins",
"mongodb.mongodb-vscode"
]
}
}
Expand Down
12 changes: 12 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,17 @@ services:
- redis-data:/data
command: dragonfly --default_lua_flags=allow-undeclared-keys

mongodb:
image: mongo:7.0.6
restart: unless-stopped
ports:
- '27017:27017'
volumes:
- mongodb-data:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example

volumes:
redis-data:
mongodb-data:
2 changes: 2 additions & 0 deletions lib/ajv/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export async function createAjv() {

ajv.addSchema(schemas)
ajv.addSchema(userSchema, 'User')
// const test = ajv.getSchema('User')
// logger.info(test?.schemaEnv)

function validateSchema(schemaId: string, data: unknown) {
const valid = ajv.validate(schemaId, data)
Expand Down
28 changes: 28 additions & 0 deletions lib/guard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import path from 'node:path'

export const alg = 'ES256'
const keysDir = path.join(__dirname, './keys')

export const publicKeyPath = path.join(keysDir, 'public')
export const privateKeyPath = path.join(keysDir, 'private')
export function loadKeys() {

}

// export async function writeKeys(obj: {
// name: string
// privateKey: jose.KeyLike
// publicKey: jose.KeyLike
// }) {

// }

// export async function generateKeyPair(name: string) {
// const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: true })

// // writeKeys({
// // name,
// // privateKey,
// // publicKey,
// // })
// }
7 changes: 7 additions & 0 deletions lib/guard/keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as jose from 'jose'

export const alg = 'ES256'

export const serverKeys = await jose.generateKeyPair(alg, { extractable: true })
export const userKeys1 = await jose.generateKeyPair(alg, { extractable: true })
export const userKeys3 = await jose.generateKeyPair(alg, { extractable: true })
28 changes: 28 additions & 0 deletions lib/guard/t1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as jose from 'jose'

const alg = 'ES256'

const keys = await jose.generateKeyPair(alg, { extractable: true })
const keys2 = await jose.generateKeyPair(alg, { extractable: true })

console.log('keys\n', await jose.exportPKCS8(keys.privateKey))
console.log('keys2\n', await jose.exportPKCS8(keys2.privateKey))

const jwt = await new jose.GeneralSign(
new TextEncoder().encode('Hello, World!'),
)
.addSignature(keys.privateKey)
.setProtectedHeader({ alg, b64: true })
.addSignature(keys2.privateKey)
.setProtectedHeader({ alg, b64: true })
.sign()

console.log('jwt', jwt)

const { payload, protectedHeader } = await jose.generalVerify(
jwt,
keys2.publicKey,
)

console.log(protectedHeader)
console.log(new TextDecoder().decode(payload))
51 changes: 51 additions & 0 deletions lib/guard/t2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as jose from 'jose'

const alg = 'ES256'
const options = {
issuer: 'urn:example:issuer',
audience: 'urn:example:audience',
}

const keys = await jose.generateKeyPair(alg, { extractable: true })
const keys2 = await jose.generateKeyPair(alg, { extractable: true })
// const keys3 = await jose.generateKeyPair(alg, { extractable: true });

const jwk1 = await jose.exportJWK(keys.publicKey).then((jwk) => {
jwk.kid = 'key1'

return jwk
})

const jwk2 = await jose.exportJWK(keys2.publicKey).then((jwk) => {
jwk.kid = 'key2'

return jwk
})

// const jwk3 = await jose.exportJWK(keys3.publicKey).then((jwk) => {
// jwk.kid = "key3";
// return jwk;
// });

const jwks = jose.createLocalJWKSet({ keys: [jwk1, jwk2] })

console.log('keys\n', await jose.exportPKCS8(keys.privateKey))
console.log('keys2\n', await jose.exportPKCS8(keys2.privateKey))

const jwt = await new jose.SignJWT({
foo: 'bar',
})
.setIssuer(options.issuer)
.setAudience(options.audience)
.setProtectedHeader({ alg, kid: 'key1' })
.setExpirationTime('10m')
.setIssuedAt()
.sign(keys.privateKey)

console.log('jwt', jwt)

const { payload, protectedHeader } = await jose
.jwtVerify(jwt, jwks, options)

console.log(protectedHeader)
console.log(payload)
22 changes: 22 additions & 0 deletions lib/guard/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function generateCombinations(test: { [key: string]: string[] }): string[][] {
let combinations: string[][] = [[]]
Object.keys(test).forEach((key) => {
const newCombinations: string[][] = []
test[key].forEach((value) => {
combinations.forEach((combination) => {
newCombinations.push([...combination, `${key}-${value}`])
})
})
combinations = newCombinations
})

return combinations
}

const test = {
size: ['xs', 's', 'm', 'l', 'xl'],
color: ['red', 'green', 'blue'],
material: ['wood', 'plastic', 'metal'],
}

console.log(generateCombinations(test))
16 changes: 16 additions & 0 deletions lib/mongo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import consola from 'consola'
import { MongoClient } from 'mongodb'

const logger = consola.withTag('mongodb')
export async function createMongoDBStore() {
const client = new MongoClient('mongodb://root:example@mongodb:27017')

await client.connect()

const db = client.db('testSozdev')
logger.debug('Connected to MongoDB', db.databaseName)

return {
data: db.collection('data'),
}
}
6 changes: 3 additions & 3 deletions lib/redis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ export async function createRedisStore() {
return items.flat() as T[]
}

const insertOne = async (id: string, data: T) => {
const pattern = formatPattern(id)
const item = { ...data, id }
const insertOne = async (_id: string, data: T) => {
const pattern = formatPattern(_id)
const item = { ...data, _id }
await connection.json.set(pattern, '$', item)

return item as T
Expand Down
2 changes: 1 addition & 1 deletion lib/transformer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { decode, encode } from '@msgpack/msgpack'
import consola from 'consola'

const logger = consola.withTag('server/trpc')
const logger = consola.withTag('server/trpc/transformer')

function uint8ArrayToString(arr: Uint8Array) {
return Array.from(arr)
Expand Down
32 changes: 16 additions & 16 deletions lib/ws/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import type { ClientOptions } from 'ws'
const logger = consola.withTag('client/ws')

type BufferLike =
| string
| Buffer
| DataView
| number
| ArrayBufferView
| Uint8Array
| ArrayBuffer
| SharedArrayBuffer
| readonly any[]
| readonly number[]
| { valueOf(): ArrayBuffer }
| { valueOf(): SharedArrayBuffer }
| { valueOf(): Uint8Array }
| { valueOf(): readonly number[] }
| { valueOf(): string }
| { [Symbol.toPrimitive](hint: string): string }
| string
| Buffer
| DataView
| number
| ArrayBufferView
| Uint8Array
| ArrayBuffer
| SharedArrayBuffer
| readonly any[]
| readonly number[]
| { valueOf(): ArrayBuffer }
| { valueOf(): SharedArrayBuffer }
| { valueOf(): Uint8Array }
| { valueOf(): readonly number[] }
| { valueOf(): string }
| { [Symbol.toPrimitive](hint: string): string }

export class WebSocketProxy extends WebSocket {
constructor(
Expand Down
96 changes: 64 additions & 32 deletions lib/ws/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,57 @@ import type { ServerOptions, WebSocket } from 'ws'
const logger = consola.withTag('ws/server')

type BufferLike =
| string
| Buffer
| DataView
| number
| ArrayBufferView
| Uint8Array
| ArrayBuffer
| SharedArrayBuffer
| readonly any[]
| readonly number[]
| { valueOf(): ArrayBuffer }
| { valueOf(): SharedArrayBuffer }
| { valueOf(): Uint8Array }
| { valueOf(): readonly number[] }
| { valueOf(): string }
| { [Symbol.toPrimitive](hint: string): string }
| string
| Buffer
| DataView
| number
| ArrayBufferView
| Uint8Array
| ArrayBuffer
| SharedArrayBuffer
| readonly any[]
| readonly number[]
| { valueOf(): ArrayBuffer }
| { valueOf(): SharedArrayBuffer }
| { valueOf(): Uint8Array }
| { valueOf(): readonly number[] }
| { valueOf(): string }
| { [Symbol.toPrimitive](hint: string): string }

export class WebSocketProxy<
T extends typeof WebSocket.WebSocket = typeof WebSocket.WebSocket,
U extends typeof IncomingMessage = typeof IncomingMessage,
T extends typeof WebSocket.WebSocket = typeof WebSocket.WebSocket,
U extends typeof IncomingMessage = typeof IncomingMessage,
> extends WebSocketServer {
constructor(
options: ServerOptions<T, U>,
options?: ServerOptions<T, U>,
callback?: () => void,
) {
super(options, callback)

logger.info('Created')
const wrappedMethods = {
on: this.customOn.bind(this),
send: this.customSend.bind(this),
}
// const wrappedMethods = {
// on: this.customOn.bind(this),
// // send: this.customSend.bind(this),
// }

return this.getProxy(this)
}

private getWrappedMethod<S extends WebSocketServer | WebSocket>(target: S, prop: string) {
const methods = {
on: this.customOn.bind(target),
send: this.customSend.bind(target),
emit: this.customSend.bind(target),
} as Record<string, (...args: any[]) => void>

return new Proxy(this, {
return methods[prop]
}

private getProxy<S extends WebSocketServer | WebSocket>(t: S) {
return new Proxy(t, {
get: (target, prop, receiver) => {
logger.info('123', prop)
if (prop === 'on' || prop === 'send') {
return wrappedMethods[prop]
return this.getWrappedMethod(target, prop)
}

return Reflect.get(target, prop, receiver)
Expand All @@ -57,12 +71,22 @@ U extends typeof IncomingMessage = typeof IncomingMessage,
event: string,
listener: (this: WebSocketServer, ...args: any[]) => void,
) {
console.log('event', event)

this.on(event, async (...args: any[]) => {
logger.info('Received', event)
if (event === 'connection') {
const arg = args as [socket: InstanceType<T>, request: InstanceType<U>]
const ws = this.getProxy(arg[0])
arg[0] = ws

listener.call(this, ...arg)

return
}

if (event === 'message') {
await sleep(100)
logger.debug('Receiving', event, JSON.parse(args[0] as string))
logger.info('Receiving', event, JSON.parse(args[0] as string))
// logger.debug('Receiving', event, JSON.parse(args[0] as string))
const [data, isBinary] = args as [BufferLike, boolean]
listener.call(this, data, isBinary)

Expand All @@ -73,9 +97,17 @@ U extends typeof IncomingMessage = typeof IncomingMessage,
})
}

private async customSend(event: string | symbol, data: BufferLike) {
private async customSend(
this: WebSocket | WebSocketServer,
data: BufferLike,
cb?: (error?: Error) => void,
) {
await sleep(100)
logger.debug('Sending', event)
this.emit(event, data)

logger.debug('Sending', data)

if ('send' in this) {
return this.send(data, cb)
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"dotenv": "^16.4.5",
"fast-glob": "^3.3.2",
"h3": "^1.11.1",
"jose": "^5.2.3",
"listhen": "^1.7.2",
"mongodb": "^6.5.0",
"nanoid": "^5.0.6",
Expand Down
Loading

0 comments on commit e185595

Please sign in to comment.