get tests passing in the browser
This commit is contained in:
@ -3,11 +3,31 @@ services:
|
||||
well-known:
|
||||
build: ./docker/well-known
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 12647:80
|
||||
|
||||
relay:
|
||||
build: ./docker/relay
|
||||
restart: on-failure
|
||||
|
||||
well-known-proxy:
|
||||
build: ./docker/cors-proxy
|
||||
restart: on-failure
|
||||
environment:
|
||||
TARGET: "well-known:80"
|
||||
ports:
|
||||
- 12648:8080
|
||||
- 12649:8000
|
||||
- 12647:80
|
||||
|
||||
relay-proxy:
|
||||
build: ./docker/cors-proxy
|
||||
restart: on-failure
|
||||
environment:
|
||||
TARGET: "relay:8080"
|
||||
ports:
|
||||
- 12648:80
|
||||
|
||||
relay-restart-proxy:
|
||||
build: ./docker/cors-proxy
|
||||
restart: on-failure
|
||||
environment:
|
||||
TARGET: "relay:8000"
|
||||
ports:
|
||||
- 12649:80
|
||||
|
4
packages/nostr/docker/cors-proxy/Dockerfile
Normal file
4
packages/nostr/docker/cors-proxy/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
||||
# An nginx proxy which adds "Access-Control-Allow-Origin: *" to responses.
|
||||
|
||||
FROM nginx
|
||||
COPY config.sh /docker-entrypoint.d/
|
24
packages/nostr/docker/cors-proxy/config.sh
Executable file
24
packages/nostr/docker/cors-proxy/config.sh
Executable file
@ -0,0 +1,24 @@
|
||||
echo "\
|
||||
map \$http_upgrade \$connection_upgrade {\
|
||||
default upgrade;\
|
||||
'' close;\
|
||||
}\
|
||||
\
|
||||
proxy_read_timeout 600s;\
|
||||
\
|
||||
server {\
|
||||
listen 80;\
|
||||
server_name default;\
|
||||
\
|
||||
location / {\
|
||||
proxy_pass http://$TARGET;\
|
||||
proxy_http_version 1.1;\
|
||||
proxy_set_header Upgrade \$http_upgrade;\
|
||||
proxy_set_header Connection \$connection_upgrade;\
|
||||
# The NIP defines that the relay should return Access-Control-Allow-Origin: * here, so don't do it twice.\n\
|
||||
if (\$http_accept != 'application/nostr+json') {\
|
||||
add_header 'Access-Control-Allow-Origin' '*';\
|
||||
}\
|
||||
}\
|
||||
}" > /etc/nginx/conf.d/default.conf
|
||||
cat /etc/nginx/conf.d/default.conf
|
@ -1 +1,2 @@
|
||||
Dockerfile
|
||||
node_modules/
|
||||
|
@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y curl nodejs npm
|
||||
RUN npm i -g yarn
|
||||
|
||||
EXPOSE 8000
|
||||
EXPOSE 8080
|
||||
|
||||
COPY . .
|
||||
USER $APP_USER
|
||||
|
@ -1,23 +1,25 @@
|
||||
{
|
||||
"name": "@snort/nostr",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w",
|
||||
"test": "ts-mocha --type-check -j 1 --timeout 5s test/*.ts",
|
||||
"build": "webpack",
|
||||
"watch": "webpack -w",
|
||||
"test": "ts-mocha --type-check -j 1 --timeout 5s test/test.*.ts",
|
||||
"test-browser": "ts-node test/browser/server.ts",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/events": "^3.0.0",
|
||||
"@types/expect": "^24.3.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@typescript-eslint/parser": "^5.53.0",
|
||||
"eslint": "^8.34.0",
|
||||
"express": "^4.18.2",
|
||||
"mocha": "^10.2.0",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"prettier": {
|
||||
@ -26,10 +28,15 @@
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.2.0",
|
||||
"@noble/secp256k1": "^1.7.1",
|
||||
"@types/chai": "^4.3.4",
|
||||
"base64-js": "^1.5.1",
|
||||
"bech32": "^2.0.0",
|
||||
"chai": "^4.3.7",
|
||||
"events": "^3.3.0",
|
||||
"isomorphic-ws": "^5.0.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"webpack": "^5.77.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"ws": "^8.12.1"
|
||||
},
|
||||
"directories": {
|
||||
|
@ -112,7 +112,7 @@ export async function aesEncryptBase64(
|
||||
sharedKey,
|
||||
{ name: "AES-CBC" },
|
||||
false,
|
||||
["encrypt", "decrypt"]
|
||||
["encrypt"]
|
||||
)
|
||||
const iv = window.crypto.getRandomValues(new Uint8Array(16))
|
||||
const data = new TextEncoder().encode(plaintext)
|
||||
@ -133,15 +133,10 @@ export async function aesEncryptBase64(
|
||||
const iv = crypto.randomFillSync(new Uint8Array(16))
|
||||
const cipher = crypto.createCipheriv(
|
||||
"aes-256-cbc",
|
||||
// TODO If this code is correct, also fix the example code
|
||||
// TODO I also this that the slice() above is incorrect because the author
|
||||
// thought this was hex but it's actually bytes so should take 32 bytes not 64
|
||||
// TODO Actually it's probably cleanest to leave out the end of the slice completely, if possible, and it should be
|
||||
Buffer.from(sharedKey),
|
||||
iv
|
||||
)
|
||||
let encrypted = cipher.update(plaintext, "utf8", "base64")
|
||||
// TODO Could save an allocation here by avoiding the +=
|
||||
encrypted += cipher.final("base64")
|
||||
return {
|
||||
data: encrypted,
|
||||
@ -158,8 +153,24 @@ export async function aesDecryptBase64(
|
||||
const sharedPoint = secp.getSharedSecret(recipient, "02" + sender)
|
||||
const sharedKey = sharedPoint.slice(1, 33)
|
||||
if (typeof window === "object") {
|
||||
// TODO Can copy this from the legacy code
|
||||
throw new NostrError("todo")
|
||||
const decodedData = base64.toByteArray(data)
|
||||
const decodedIv = base64.toByteArray(iv)
|
||||
const importedKey = await window.crypto.subtle.importKey(
|
||||
"raw",
|
||||
sharedKey,
|
||||
{ name: "AES-CBC" },
|
||||
false,
|
||||
["decrypt"]
|
||||
)
|
||||
const plaintext = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-CBC",
|
||||
iv: decodedIv,
|
||||
},
|
||||
importedKey,
|
||||
decodedData
|
||||
)
|
||||
return new TextDecoder().decode(plaintext)
|
||||
} else {
|
||||
const crypto = await import("crypto")
|
||||
const decipher = crypto.createDecipheriv(
|
||||
|
29
packages/nostr/test/browser/index.html
Normal file
29
packages/nostr/test/browser/index.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Tests</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
|
||||
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
||||
|
||||
<script class="mocha-init">
|
||||
mocha.setup({
|
||||
ui: "bdd",
|
||||
timeout: "5s",
|
||||
})
|
||||
mocha.checkLeaks()
|
||||
</script>
|
||||
|
||||
<!-- The server replaces the following line with <script> tags for all tests. -->
|
||||
<!-- TESTS -->
|
||||
|
||||
<script class="mocha-exec">
|
||||
mocha.run()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
45
packages/nostr/test/browser/server.ts
Normal file
45
packages/nostr/test/browser/server.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Serve tests in the browser.
|
||||
*/
|
||||
|
||||
import express from "express"
|
||||
import * as path from "path"
|
||||
import * as fs from "fs"
|
||||
|
||||
const port = 33543
|
||||
const app = express()
|
||||
|
||||
app.use("/", (req: express.Request, res: express.Response) => {
|
||||
if (req.path === "/") {
|
||||
const index = fs.readFileSync(path.join(__dirname, "index.html"), {
|
||||
encoding: "utf8",
|
||||
})
|
||||
const tests = fs
|
||||
.readdirSync(path.join(__dirname, "..", "..", "dist", "test"))
|
||||
.filter(
|
||||
(f) =>
|
||||
f.startsWith("test.") && !f.endsWith(".map") && !f.endsWith(".d.ts")
|
||||
)
|
||||
.map((src) => `<script src="${src}"></script>`)
|
||||
.join("\n")
|
||||
res.set("Content-Type", "text/html")
|
||||
res.send(index.replace("<!-- TESTS -->", tests))
|
||||
res.end()
|
||||
} else if (req.path === "/favicon.ico") {
|
||||
res.status(404)
|
||||
res.end()
|
||||
} else {
|
||||
const file = path.join(__dirname, "..", "..", "dist", "test", req.path)
|
||||
res.sendFile(file, (err) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
res.status(404)
|
||||
}
|
||||
res.end()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Browser tests: http://localhost:${port}`)
|
||||
})
|
@ -69,12 +69,8 @@ export async function setup(
|
||||
}
|
||||
|
||||
async function restartRelay() {
|
||||
// Make a request to the endpoint which will crash the process and cause it to restart.
|
||||
try {
|
||||
await fetch("http://localhost:12649")
|
||||
} catch (e) {
|
||||
// Since the process exits, an error is expected.
|
||||
}
|
||||
// Make a request to the endpoint which will exit the process and cause it to restart.
|
||||
await fetch("http://localhost:12649")
|
||||
|
||||
// Wait until the relay process is ready.
|
||||
for (;;) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import assert from "assert"
|
||||
import { assert } from "chai"
|
||||
import { EventKind } from "../src/event"
|
||||
import { createContactList } from "../src/event/contact-list"
|
||||
import { setup } from "./setup"
|
@ -1,6 +1,6 @@
|
||||
import { assert } from "chai"
|
||||
import { EventKind } from "../src/event"
|
||||
import { parsePublicKey } from "../src/crypto"
|
||||
import assert from "assert"
|
||||
import { setup } from "./setup"
|
||||
import { createTextNote } from "../src/event/text"
|
||||
import { createDeletion } from "../src/event/deletion"
|
@ -1,6 +1,6 @@
|
||||
import { assert } from "chai"
|
||||
import { EventKind } from "../src/event"
|
||||
import { parsePublicKey } from "../src/crypto"
|
||||
import assert from "assert"
|
||||
import { setup } from "./setup"
|
||||
import { createDirectMessage } from "../src/event/direct-message"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import assert from "assert"
|
||||
import { assert } from "chai"
|
||||
import { defined } from "../src/common"
|
||||
import { EventKind } from "../src/event"
|
||||
import { createSetMetadata } from "../src/event/set-metadata"
|
@ -1,4 +1,4 @@
|
||||
import assert from "assert"
|
||||
import { assert } from "chai"
|
||||
import { Nostr } from "../src/client"
|
||||
import { relayUrl } from "./setup"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import assert from "assert"
|
||||
import { assert } from "chai"
|
||||
import { Nostr } from "../src/client"
|
||||
import { setup } from "./setup"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { assert } from "chai"
|
||||
import { EventKind } from "../src/event"
|
||||
import { parsePublicKey } from "../src/crypto"
|
||||
import assert from "assert"
|
||||
import { setup } from "./setup"
|
||||
import { createSetMetadata } from "../src/event/set-metadata"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { assert } from "chai"
|
||||
import { EventKind } from "../src/event"
|
||||
import { parsePublicKey } from "../src/crypto"
|
||||
import assert from "assert"
|
||||
import { setup } from "./setup"
|
||||
import { createTextNote } from "../src/event/text"
|
||||
|
@ -1,17 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"noImplicitOverride": true,
|
||||
"module": "CommonJS",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"composite": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"noImplicitOverride": true,
|
||||
"module": "CommonJS",
|
||||
"strict": true
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src", "test"]
|
||||
}
|
||||
|
31
packages/nostr/webpack.config.js
Normal file
31
packages/nostr/webpack.config.js
Normal file
@ -0,0 +1,31 @@
|
||||
const fs = require("fs")
|
||||
|
||||
const entry = {
|
||||
lib: "./src/index.ts",
|
||||
}
|
||||
|
||||
for (const file of fs.readdirSync("./test/")) {
|
||||
if (/.ts$/.test(file)) {
|
||||
const name = file.replace(/.ts$/, "")
|
||||
entry[`test/${name}`] = `./test/${file}`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mode: process.env.NODE_ENV || "development",
|
||||
devtool: "inline-source-map",
|
||||
entry,
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
fallback: {
|
||||
crypto: false,
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [{ test: /\.ts$/, use: "ts-loader" }],
|
||||
},
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
path: `${__dirname}/dist`,
|
||||
},
|
||||
}
|
Reference in New Issue
Block a user