mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-22 09:57:00 +01:00
Added CORS middleware. Updated umami script.
This commit is contained in:
parent
bb04015b46
commit
58a1c63407
20
lib/middleware.js
Normal file
20
lib/middleware.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import cors from 'cors';
|
||||||
|
|
||||||
|
export function use(middleware) {
|
||||||
|
return (req, res) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
middleware(req, res, result => {
|
||||||
|
if (result instanceof Error) {
|
||||||
|
return reject(result);
|
||||||
|
}
|
||||||
|
return resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const allowPost = use(
|
||||||
|
cors({
|
||||||
|
origin: '*',
|
||||||
|
methods: ['POST', 'OPTIONS'],
|
||||||
|
}),
|
||||||
|
);
|
75
lib/utils.js
75
lib/utils.js
@ -61,48 +61,55 @@ export async function getCountry(req, ip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function parseSessionRequest(req) {
|
export async function parseSessionRequest(req) {
|
||||||
const ip = getIpAddress(req);
|
if (req.method === 'POST') {
|
||||||
const { website_id, screen, language } = req.body;
|
const ip = getIpAddress(req);
|
||||||
const { userAgent, browser, os } = getDevice(req);
|
const { website_id, hostname, screen, language } = req.body;
|
||||||
const country = await getCountry(req, ip);
|
const { userAgent, browser, os } = getDevice(req);
|
||||||
const session_id = hash(`${website_id}${ip}${userAgent}${os}`);
|
const country = await getCountry(req, ip);
|
||||||
|
const session_id = hash(`${website_id}${hostname}${ip}${userAgent}${os}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
website_id,
|
website_id,
|
||||||
session_id,
|
session_id,
|
||||||
browser,
|
hostname,
|
||||||
os,
|
browser,
|
||||||
screen,
|
os,
|
||||||
language,
|
screen,
|
||||||
country,
|
language,
|
||||||
};
|
country,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseCollectRequest(req) {
|
export function parseCollectRequest(req) {
|
||||||
const { type, payload } = req.body;
|
if (req.method === 'POST') {
|
||||||
|
const { type, payload } = req.body;
|
||||||
|
|
||||||
if (payload.session) {
|
if (payload.session) {
|
||||||
const {
|
const {
|
||||||
url,
|
|
||||||
referrer,
|
|
||||||
session: { website_id, session_id, time, hash: validationHash },
|
|
||||||
} = payload;
|
|
||||||
|
|
||||||
if (
|
|
||||||
validHash(website_id) &&
|
|
||||||
validHash(session_id) &&
|
|
||||||
validHash(validationHash) &&
|
|
||||||
hash(`${website_id}${session_id}${time}`) === validationHash
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
valid: true,
|
|
||||||
type,
|
|
||||||
session_id,
|
|
||||||
url,
|
url,
|
||||||
referrer,
|
referrer,
|
||||||
};
|
session: { website_id, session_id, time, hash: validationHash },
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
if (
|
||||||
|
validHash(website_id) &&
|
||||||
|
validHash(session_id) &&
|
||||||
|
validHash(validationHash) &&
|
||||||
|
hash(`${website_id}${session_id}${time}`) === validationHash
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
success: 1,
|
||||||
|
type,
|
||||||
|
session_id,
|
||||||
|
url,
|
||||||
|
referrer,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { valid: false };
|
return { success: 0 };
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"@prisma/client": "2.2.2",
|
"@prisma/client": "2.2.2",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"date-fns": "^2.14.0",
|
"date-fns": "^2.14.0",
|
||||||
"detect-browser": "^5.1.1",
|
"detect-browser": "^5.1.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import { parseCollectRequest } from 'lib/utils';
|
import { parseCollectRequest } from 'lib/utils';
|
||||||
import { savePageView } from 'lib/db';
|
import { savePageView } from 'lib/db';
|
||||||
|
import { allowPost } from 'lib/middleware';
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
|
await allowPost(req, res);
|
||||||
|
|
||||||
const values = parseCollectRequest(req);
|
const values = parseCollectRequest(req);
|
||||||
|
|
||||||
if (values.valid) {
|
if (values.success) {
|
||||||
const { type, session_id, url, referrer } = values;
|
const { type, session_id, url, referrer } = values;
|
||||||
|
|
||||||
if (type === 'pageview') {
|
if (type === 'pageview') {
|
||||||
await savePageView(session_id, url, referrer);
|
await savePageView(session_id, url, referrer).catch(() => {
|
||||||
|
values.success = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
res.status(200).json({ success: values.success });
|
||||||
|
|
||||||
res.status(200).json({ status: values.valid });
|
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { getWebsite, getSession, createSession } from 'lib/db';
|
import { getWebsite, getSession, createSession } from 'lib/db';
|
||||||
import { hash, parseSessionRequest } from 'lib/utils';
|
import { hash, parseSessionRequest } from 'lib/utils';
|
||||||
|
import { allowPost } from 'lib/middleware';
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
let result = { time: Date.now() };
|
await allowPost(req, res);
|
||||||
|
|
||||||
|
let result = { success: 0, time: Date.now() };
|
||||||
|
|
||||||
const {
|
const {
|
||||||
website_id,
|
website_id,
|
||||||
session_id,
|
session_id,
|
||||||
|
hostname,
|
||||||
browser,
|
browser,
|
||||||
os,
|
os,
|
||||||
screen,
|
screen,
|
||||||
@ -13,24 +18,32 @@ export default async (req, res) => {
|
|||||||
country,
|
country,
|
||||||
} = await parseSessionRequest(req);
|
} = await parseSessionRequest(req);
|
||||||
|
|
||||||
const website = await getWebsite(website_id);
|
if (website_id && session_id) {
|
||||||
|
const website = await getWebsite(website_id);
|
||||||
|
|
||||||
if (website) {
|
if (website) {
|
||||||
const session = await getSession(session_id);
|
const session = await getSession(session_id);
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
await createSession(website_id, session_id, { browser, os, screen, language, country });
|
await createSession(website_id, session_id, {
|
||||||
|
hostname,
|
||||||
|
browser,
|
||||||
|
os,
|
||||||
|
screen,
|
||||||
|
language,
|
||||||
|
country,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
result = {
|
||||||
|
...result,
|
||||||
|
success: 1,
|
||||||
|
session_id,
|
||||||
|
website_id,
|
||||||
|
hash: hash(`${website_id}${session_id}${result.time}`),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
result = {
|
|
||||||
...result,
|
|
||||||
session_id,
|
|
||||||
website_id,
|
|
||||||
hash: hash(`${website_id}${session_id}${result.time}`),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
|
|
||||||
res.status(200).json(result);
|
res.status(200).json(result);
|
||||||
};
|
};
|
||||||
|
@ -34,6 +34,7 @@ model session {
|
|||||||
browser String?
|
browser String?
|
||||||
country String?
|
country String?
|
||||||
created_at DateTime? @default(now())
|
created_at DateTime? @default(now())
|
||||||
|
hostname String?
|
||||||
language String?
|
language String?
|
||||||
os String?
|
os String?
|
||||||
screen String?
|
screen String?
|
||||||
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -11,16 +11,37 @@ const {
|
|||||||
document,
|
document,
|
||||||
} = window;
|
} = window;
|
||||||
|
|
||||||
function post(url, params) {
|
const post = (url, params) =>
|
||||||
return fetch(url, {
|
fetch(url, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
headers: {
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: params,
|
body: JSON.stringify(params),
|
||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
|
||||||
|
const createSession = data =>
|
||||||
|
post(`${HOST_URL}/api/session`, data).then(({ success, ...session }) => {
|
||||||
|
if (success) {
|
||||||
|
store.setItem(SESSION_VAR, JSON.stringify(session));
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getSession = () => JSON.parse(store.getItem(SESSION_VAR));
|
||||||
|
|
||||||
|
const pageView = (url, referrer) =>
|
||||||
|
post(`${HOST_URL}/api/collect`, {
|
||||||
|
type: 'pageview',
|
||||||
|
payload: { url, referrer, session: getSession() },
|
||||||
|
}).then(({ success }) => {
|
||||||
|
if (!success) {
|
||||||
|
store.removeItem(SESSION_VAR);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
});
|
||||||
|
|
||||||
const script = document.querySelector('script[data-website-id]');
|
const script = document.querySelector('script[data-website-id]');
|
||||||
|
|
||||||
@ -31,26 +52,12 @@ if (script) {
|
|||||||
const referrer = document.referrer;
|
const referrer = document.referrer;
|
||||||
const screen = `${width}x${height}`;
|
const screen = `${width}x${height}`;
|
||||||
const url = `${pathname}${search}`;
|
const url = `${pathname}${search}`;
|
||||||
|
const data = { website_id, hostname, url, screen, language };
|
||||||
|
|
||||||
if (!store.getItem(SESSION_VAR)) {
|
if (!store.getItem(SESSION_VAR)) {
|
||||||
post(`${HOST_URL}/api/session`, {
|
createSession(data).then(success => success && pageView(url, referrer));
|
||||||
website_id,
|
} else {
|
||||||
hostname,
|
pageView(url, referrer).then(success => !success && createSession(data));
|
||||||
url,
|
|
||||||
screen,
|
|
||||||
language,
|
|
||||||
}).then(session => {
|
|
||||||
store.setItem(SESSION_VAR, JSON.stringify(session));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post(`${HOST_URL}/api/collect`, {
|
|
||||||
type: 'pageview',
|
|
||||||
payload: { url, referrer, session: JSON.parse(store.getItem(SESSION_VAR)) },
|
|
||||||
}).then(response => {
|
|
||||||
if (!response.status) {
|
|
||||||
store.removeItem(SESSION_VAR);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
create table website (
|
create table website (
|
||||||
website_id uuid primary key,
|
website_id uuid primary key,
|
||||||
hostname varchar(255) unique not null,
|
hostname varchar(100) unique not null,
|
||||||
created_at timestamp with time zone default current_timestamp
|
created_at timestamp with time zone default current_timestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -8,6 +8,7 @@ create table session (
|
|||||||
session_id uuid primary key,
|
session_id uuid primary key,
|
||||||
website_id uuid references website(website_id) on delete cascade,
|
website_id uuid references website(website_id) on delete cascade,
|
||||||
created_at timestamp with time zone default current_timestamp,
|
created_at timestamp with time zone default current_timestamp,
|
||||||
|
hostname varchar(100),
|
||||||
browser varchar(20),
|
browser varchar(20),
|
||||||
os varchar(20),
|
os varchar(20),
|
||||||
screen varchar(11),
|
screen varchar(11),
|
||||||
|
15
yarn.lock
15
yarn.lock
@ -2619,6 +2619,14 @@ core-util-is@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||||
|
|
||||||
|
cors@^2.8.5:
|
||||||
|
version "2.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||||
|
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||||
|
dependencies:
|
||||||
|
object-assign "^4"
|
||||||
|
vary "^1"
|
||||||
|
|
||||||
cosmiconfig@^5.0.0:
|
cosmiconfig@^5.0.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
|
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
|
||||||
@ -5513,7 +5521,7 @@ num2fraction@^1.2.2:
|
|||||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||||
integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
|
integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
|
||||||
|
|
||||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||||
@ -8386,6 +8394,11 @@ validate-npm-package-license@^3.0.1:
|
|||||||
spdx-correct "^3.0.0"
|
spdx-correct "^3.0.0"
|
||||||
spdx-expression-parse "^3.0.0"
|
spdx-expression-parse "^3.0.0"
|
||||||
|
|
||||||
|
vary@^1:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||||
|
|
||||||
vendors@^1.0.0:
|
vendors@^1.0.0:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
|
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
|
||||||
|
Loading…
Reference in New Issue
Block a user