diff --git a/lib/request.js b/lib/request.js index 904611f0..35545006 100644 --- a/lib/request.js +++ b/lib/request.js @@ -68,13 +68,13 @@ export async function getCountry(req, ip) { lookup.close(); - return result.country.iso_code; + return result?.country?.iso_code; } export async function getClientInfo(req, { screen }) { + const userAgent = req.headers['user-agent']; const ip = getIpAddress(req); const country = await getCountry(req, ip); - const userAgent = req.headers['user-agent']; const browser = browserName(userAgent); const os = detectOS(userAgent); const device = getDevice(screen, browser, os); diff --git a/lib/session.js b/lib/session.js index 9e57652a..ef9f403f 100644 --- a/lib/session.js +++ b/lib/session.js @@ -1,6 +1,6 @@ import { getWebsiteByUuid, getSessionByUuid, createSession } from 'lib/queries'; import { getClientInfo } from 'lib/request'; -import { uuid, isValidId, parseToken } from 'lib/crypto'; +import { uuid, isValidId } from 'lib/crypto'; export async function verifySession(req) { const { payload } = req.body; @@ -9,50 +9,42 @@ export async function verifySession(req) { throw new Error('Invalid request'); } - const { website: website_uuid, hostname, screen, language, session } = payload; + const { website: website_uuid, hostname, screen, language } = payload; if (!isValidId(website_uuid)) { throw new Error(`Invalid website: ${website_uuid}`); } - const token = await parseToken(session); + const { userAgent, browser, os, ip, country, device } = await getClientInfo(req, payload); - if (!token || token.website_uuid !== website_uuid) { - const { userAgent, browser, os, ip, country, device } = await getClientInfo(req, payload); + const website = await getWebsiteByUuid(website_uuid); - const website = await getWebsiteByUuid(website_uuid); - - if (!website) { - throw new Error(`Website not found: ${website_uuid}`); - } - - const { website_id } = website; - const session_uuid = uuid(website_id, hostname, ip, userAgent, os); - - let session = await getSessionByUuid(session_uuid); - - if (!session) { - session = await createSession(website_id, { - session_uuid, - hostname, - browser, - os, - screen, - language, - country, - device, - }); - } - - const { session_id } = session; - - return { - website_id, - website_uuid, - session_id, - session_uuid, - }; + if (!website) { + throw new Error(`Website not found: ${website_uuid}`); } - return token; + const { website_id } = website; + const session_uuid = uuid(website_id, hostname, ip, userAgent, os); + + let session = await getSessionByUuid(session_uuid); + + if (!session) { + session = await createSession(website_id, { + session_uuid, + hostname, + browser, + os, + screen, + language, + country, + device, + }); + } + + const { session_id } = session; + + return { + website_id, + session_id, + }; } diff --git a/package.json b/package.json index 32369d71..5f7be4d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.10.4", + "version": "0.11.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT", diff --git a/pages/api/collect.js b/pages/api/collect.js index 07e513d4..56d2ea79 100644 --- a/pages/api/collect.js +++ b/pages/api/collect.js @@ -1,16 +1,15 @@ import { savePageView, saveEvent } from 'lib/queries'; import { useCors, useSession } from 'lib/middleware'; -import { createToken } from 'lib/crypto'; import { ok, badRequest } from 'lib/response'; export default async (req, res) => { await useCors(req, res); await useSession(req, res); - const { session } = req; - const token = await createToken(session); - const { website_id, session_id } = session; const { type, payload } = req.body; + const { + session: { website_id, session_id }, + } = req; if (type === 'pageview') { const { url, referrer } = payload; @@ -24,5 +23,5 @@ export default async (req, res) => { return badRequest(res); } - return ok(res, { session: token }); + return ok(res); }; diff --git a/public/umami.js b/public/umami.js index 7b2fb336..64a68198 100644 --- a/public/umami.js +++ b/public/umami.js @@ -1 +1 @@ -!function(){"use strict";function e(e){var t=this.constructor;return this.then((function(n){return t.resolve(e()).then((function(){return n}))}),(function(n){return t.resolve(e()).then((function(){return t.reject(n)}))}))}var t=setTimeout;function n(e){return Boolean(e&&void 0!==e.length)}function r(){}function o(e){if(!(this instanceof o))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],f(e,this)}function i(e,t){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,o._immediateFn((function(){var n=1===e._state?t.onFulfilled:t.onRejected;if(null!==n){var r;try{r=n(e._value)}catch(e){return void s(t.promise,e)}u(t.promise,r)}else(1===e._state?u:s)(t.promise,e._value)}))):e._deferreds.push(t)}function u(e,t){try{if(t===e)throw new TypeError("A promise cannot be resolved with itself.");if(t&&("object"==typeof t||"function"==typeof t)){var n=t.then;if(t instanceof o)return e._state=3,e._value=t,void a(e);if("function"==typeof n)return void f((r=n,i=t,function(){r.apply(i,arguments)}),e)}e._state=1,e._value=t,a(e)}catch(t){s(e,t)}var r,i}function s(e,t){e._state=2,e._value=t,a(e)}function a(e){2===e._state&&0===e._deferreds.length&&o._immediateFn((function(){e._handled||o._unhandledRejectionFn(e._value)}));for(var t=0,n=e._deferreds.length;t { +(window => { const { screen: { width, height }, navigator: { language }, location: { hostname, pathname, search }, - localStorage: store, document, history, } = window; const script = document.querySelector('script[data-website-id]'); - const website = script && script.getAttribute('data-website-id'); + + if (!script) return; + + const website = script.getAttribute('data-website-id'); const hostUrl = new URL(script.src).origin; const screen = `${width}x${height}`; const listeners = []; @@ -21,9 +23,10 @@ import { post, hook } from '../lib/web'; let currentUrl = `${pathname}${search}`; let currentRef = document.referrer; + /* Collect metrics */ + const collect = (type, params) => { const payload = { - session: store.getItem(sessionKey), url: currentUrl, referrer: currentRef, website, @@ -41,7 +44,7 @@ import { post, hook } from '../lib/web'; return post(`${hostUrl}/api/collect`, { type, payload, - }).then(({ session }) => session && store.setItem(sessionKey, session)); + }); }; const pageView = () => collect('pageview').then(() => setTimeout(loadEvents, 300)); @@ -86,4 +89,4 @@ import { post, hook } from '../lib/web'; /* Start */ pageView(); -})(window, 'umami.session'); +})(window);