Moved files here
This commit is contained in:
commit
c8965f7aee
7 files changed
+250
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
.idea
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Hello Bulma!</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="section">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">
|
||||||
|
Hello World
|
||||||
|
</h1>
|
||||||
|
<p class="subtitle">
|
||||||
|
My first website with <strong>Bulma</strong>!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
import { Router, Context, Request } from "https://deno.land/x/oak/mod.ts";
|
||||||
|
import { Pool } from "https://deno.land/x/postgres@v0.17.0/mod.ts";
|
||||||
|
import { createBundle } from "./bundle.ts";
|
||||||
|
const clientBundle = createBundle(
|
||||||
|
new URL("./client.js", import.meta.url),
|
||||||
|
new URL("../import_map.json", import.meta.url),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
export function buildApp(pool: Pool): Router{
|
||||||
|
const router = new Router();
|
||||||
|
function getHeaders(request: Request): Record<string, string>{
|
||||||
|
const ret: Record<string, string> = {};
|
||||||
|
for (const [k, v] of request.headers.entries()) {
|
||||||
|
ret[k] = v;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
router.post("/api/v1/spy", async (ctx: Context) => {
|
||||||
|
const payload = await ctx.request.body().value;
|
||||||
|
payload.request = {
|
||||||
|
ip: ctx.request.ip,
|
||||||
|
ips: ctx.request.ips,
|
||||||
|
url: ctx.request.url.toString(),
|
||||||
|
date: Date.now(),
|
||||||
|
method: ctx.request.method,
|
||||||
|
headers: getHeaders(ctx.request),
|
||||||
|
};
|
||||||
|
const client = await pool.connect();
|
||||||
|
try{
|
||||||
|
const query ="INSERT INTO blog_statistics(raw_data) VALUES ($1)";
|
||||||
|
await client.queryArray(query, [payload]);
|
||||||
|
ctx.response.body = '{}';
|
||||||
|
}finally {
|
||||||
|
client.release()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/stats", (ctx:Context) => {
|
||||||
|
ctx.response.body = 'hello world'
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/toto.js", async (ctx: Context) => {
|
||||||
|
|
||||||
|
ctx.response.body = await clientBundle;
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* This part of the code is based on the way `fresh` is bundling the code.
|
||||||
|
* See https://github.com/denoland/fresh/blob/main/src/server/bundle.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @deno-types="https://deno.land/x/esbuild@v0.14.51/mod.d.ts"
|
||||||
|
import * as esbuildNative from "https://deno.land/x/esbuild@v0.14.51/mod.js";
|
||||||
|
import * as esbuildWasm from "https://deno.land/x/esbuild@v0.14.51/wasm.js";
|
||||||
|
import { denoPlugin } from "https://deno.land/x/esbuild_deno_loader@0.5.2/mod.ts";
|
||||||
|
|
||||||
|
const esbuild: typeof esbuildWasm = Deno.run === undefined
|
||||||
|
? esbuildWasm
|
||||||
|
: esbuildNative;
|
||||||
|
|
||||||
|
let esbuildInitialized = false;
|
||||||
|
async function verifyEsbuildInitialized() {
|
||||||
|
if (esbuildInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(new Date(), "start initializing esbuild");
|
||||||
|
if (Deno.run === undefined) {
|
||||||
|
const wasmURL = new URL("./esbuild@v0.14.51.wasm", import.meta.url).href;
|
||||||
|
const resp = await fetch(wasmURL);
|
||||||
|
const wasm = new Response(resp.body, {
|
||||||
|
headers: { "Content-Type": "application/wasm" },
|
||||||
|
});
|
||||||
|
const wasmModule = await WebAssembly.compileStreaming(wasm);
|
||||||
|
await esbuild.initialize({
|
||||||
|
wasmModule,
|
||||||
|
worker: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await esbuild.initialize({});
|
||||||
|
}
|
||||||
|
esbuildInitialized = true;
|
||||||
|
console.log(new Date(), "esbuild initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createBundle(
|
||||||
|
entryPoint: URL,
|
||||||
|
importMapURL: URL,
|
||||||
|
isDev?: boolean,
|
||||||
|
) {
|
||||||
|
await verifyEsbuildInitialized();
|
||||||
|
console.log(new Date(), "Bundling", entryPoint.href);
|
||||||
|
const absWorkingDir = Deno.cwd();
|
||||||
|
const res = await esbuild.build({
|
||||||
|
bundle: true,
|
||||||
|
entryPoints: [entryPoint.href],
|
||||||
|
platform: "neutral",
|
||||||
|
treeShaking: true,
|
||||||
|
minify: !isDev,
|
||||||
|
sourcemap: isDev ? "inline" : false,
|
||||||
|
outfile: "",
|
||||||
|
absWorkingDir,
|
||||||
|
outdir: ".",
|
||||||
|
target: ["chrome99", "firefox99", "safari15"],
|
||||||
|
write: false,
|
||||||
|
format: "esm",
|
||||||
|
plugins: [denoPlugin({ importMapURL })],
|
||||||
|
splitting: false,
|
||||||
|
jsx: "automatic",
|
||||||
|
jsxImportSource: "react",
|
||||||
|
});
|
||||||
|
if (res.errors.length > 0) {
|
||||||
|
throw res.errors;
|
||||||
|
}
|
||||||
|
console.log(new Date(), "Finished bundling", entryPoint.href);
|
||||||
|
return res.outputFiles[0].text;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
(function(window){
|
||||||
|
const SPY_KEY = 'spy-key';
|
||||||
|
|
||||||
|
function randomWord(length) {
|
||||||
|
let result = '';
|
||||||
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
for(let i = 0; i < length; i++){
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getSpyKey(){
|
||||||
|
return window.localStorage.getItem(SPY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateSpyKey(){
|
||||||
|
const spyKey = randomWord(80);
|
||||||
|
window.localStorage.setItem(SPY_KEY, spyKey);
|
||||||
|
return spyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrCreateSpyKey(){
|
||||||
|
return getSpyKey() || generateSpyKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function canvasFingerprint() {
|
||||||
|
|
||||||
|
let canvasElement = document.createElement('canvas');
|
||||||
|
let canvasContext = canvasElement.getContext('2d');
|
||||||
|
canvasContext.fillStyle = 'rgba(0,0,0,0.5)';
|
||||||
|
|
||||||
|
canvasContext.fillText('Hello mon coco ☀️ 🙋🏽', 0, 100)
|
||||||
|
|
||||||
|
canvasContext.fillText('d\ne\tdkd', 50, 50)
|
||||||
|
canvasContext.beginPath()
|
||||||
|
canvasContext.arc(20, 20, 20, 0, 6)
|
||||||
|
canvasContext.fillStyle = 'red'
|
||||||
|
canvasContext.fill()
|
||||||
|
let canvasData = (new TextEncoder).encode(canvasElement.toDataURL())
|
||||||
|
let canvasFingerprint = await crypto.subtle.digest('sha-1', canvasData)
|
||||||
|
|
||||||
|
canvasFingerprint = new Uint8Array(canvasFingerprint)
|
||||||
|
canvasFingerprint = String.fromCharCode(...canvasFingerprint)
|
||||||
|
canvasFingerprint = btoa(canvasFingerprint)
|
||||||
|
|
||||||
|
return canvasFingerprint
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSizes(){
|
||||||
|
return {
|
||||||
|
'window_innerWidth': window.innerWidth,
|
||||||
|
'window_outerWidth': window.outerWidth,
|
||||||
|
'window_innerHeight': window.innerHeight,
|
||||||
|
'window_outerHeight': window.outerHeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPayload(){
|
||||||
|
return {
|
||||||
|
windowPerformance: window.performance,
|
||||||
|
sizes: getSizes(),
|
||||||
|
localStorageSpyKey: getOrCreateSpyKey(),
|
||||||
|
canvasFingerPrint: await canvasFingerprint(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publishPayload(payload){
|
||||||
|
const rawResponse = await fetch('/api/v1/spy', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
const content = await rawResponse.json();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function main(){
|
||||||
|
await publishPayload(await getPayload());
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(main, 1000);
|
||||||
|
})(window)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
import { Application, Router, Context, Request } from "https://deno.land/x/oak/mod.ts";
|
||||||
|
import { Pool } from "https://deno.land/x/postgres@v0.17.0/mod.ts";
|
||||||
|
import {buildApp} from "./app.ts";
|
||||||
|
import { oakCors } from "https://deno.land/x/cors/mod.ts";
|
||||||
|
import staticFiles from "https://deno.land/x/static_files@1.1.6/mod.ts";
|
||||||
|
|
||||||
|
|
||||||
|
const pool = new Pool(Deno.env.get("POSTGRES_URL"), 2, true);
|
||||||
|
const app = new Application();
|
||||||
|
|
||||||
|
app.use(oakCors({origin: /^.+localhost:8080$/,}));
|
||||||
|
app.use(buildApp(pool).routes());
|
||||||
|
app.use(staticFiles("public", {brotli: true, fetch: true}));
|
||||||
|
|
||||||
|
await app.listen({port:8000});
|
||||||
Reference in new issue
Block a user