Skip to content

Commit

Permalink
feat: collect device fingerprint
Browse files Browse the repository at this point in the history
  • Loading branch information
7sete7 committed Nov 18, 2024
1 parent 8b52ace commit 4b0e6f2
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 10 deletions.
9 changes: 6 additions & 3 deletions src/imports/auth/login/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ interface LoginParams {
resolution?: { width: number; height: number } | string;
userAgent?: string;
source?: string;
fingerprint?: string;
}

interface accessLog {
interface AccessLog {
_createdAt: Date;
_updatedAt: Date;
ip?: string | string[];
Expand All @@ -31,6 +32,7 @@ interface accessLog {
resolution?: { width: number; height: number };
reason?: string;
source?: string;
fingerprint?: string;
__from?: string;
_user?: [
{
Expand All @@ -41,10 +43,10 @@ interface accessLog {
];
}

export async function login({ ip, user, password, password_SHA256, geolocation, resolution, userAgent, source }: LoginParams) {
export async function login({ ip, user, password, password_SHA256, geolocation, resolution, userAgent, source, fingerprint }: LoginParams) {
const ua = new UAParser(userAgent ?? 'API Call').getResult();

const accessLog: accessLog = {
const accessLog: AccessLog = {
_createdAt: new Date(),
_updatedAt: new Date(),
ip,
Expand All @@ -54,6 +56,7 @@ export async function login({ ip, user, password, password_SHA256, geolocation,
os: ua.os.name,
platform: ua.device.type,
source,
fingerprint,
__from: 'login',
};

Expand Down
1 change: 1 addition & 0 deletions src/imports/model/Namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const NamespaceSchema = z
.object({
type: z.literal('Namespace'),
trackUserGeolocation: z.boolean().optional(),
trackUserFingerprint: z.boolean().optional(),
loginExpiration: z.number().optional(),
dateFormat: z.string().optional(),
logoURL: z.string().optional(),
Expand Down
26 changes: 26 additions & 0 deletions src/private/templates/fingerprint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(function () {
if (window.localStorage) {
const MAX_FP_AGE = 10 * 24 * 60 * 60 * 1000; // 10 days
window.fingerprint = localStorage.getItem('_k.fp');

if (window.fingerprint) {
var fpDate = localStorage.getItem('_k.fp.date');

if (fpDate && Date.now() - Number(fpDate) > MAX_FP_AGE) {
localStorage.removeItem('_k.fp');
localStorage.removeItem('_k.fp.date');
window.fingerprint = null;
}
}

if (!window.fingerprint) {
const fpPromise = window.FingerprintJS.load();

fpPromise.then((fp) => fp.get()).then((result) => {
window.fingerprint = result.visitorId;
localStorage.setItem('_k.fp', result.visitorId);
localStorage.setItem('_k.fp.date', new Date().getTime().toString());
});
}
}
})();
4 changes: 4 additions & 0 deletions src/private/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
integrity="sha512-Kq3/MTxphzXJIRDWtrpLhhNnLDPiBXPMKkx/KogMYZO92Geor9j8sJguZ1OozBS+YVmVKo2HEx2gZfGOQBFM8A=="
crossorigin="anonymous"
></script>
{{#if collectFingerprint}}
<script src="https://openfpcdn.io/fingerprintjs/v4/iife.min.js"></script>
<script src="/fp.js"></script>
{{/if}}
<script type="text/javascript">
window.BLOB_URL = '{{blobUrl}}';
window.PREVIEW_URL = '{{previewUrl}}';
Expand Down
4 changes: 4 additions & 0 deletions src/private/templates/login/login.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
<!--[if IE]>
<link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
<![endif]-->
{{#if collectFingerprint}}
<script src="https://openfpcdn.io/fingerprintjs/v4/iife.min.js"></script>
<script src="/fp.js"></script>
{{/if}}
</head>
<body>
<script>
Expand Down
2 changes: 2 additions & 0 deletions src/private/templates/login/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ function clearCookie(cookie, clearMyKonecty) {
password_SHA256: SHA256($('#password').val().trim()),
ns: $('#namespace').val().replace(/[\s-]/g, ''),
geolocation: geolocation,
fingerprint: window.fingerprint,
source: 'interface',
resolution: JSON.stringify({
height: screen.height,
width: screen.width,
Expand Down
4 changes: 3 additions & 1 deletion src/server/routes/rest/auth/authApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ export const authApi: FastifyPluginCallback = (fastify, _, done) => {
resolution?: { width: number; height: number };
password_SHA256?: string;
source?: string;
fingerprint?: string;
};
}>('/rest/auth/login', async function (req, reply) {
// Map body parameters
const { user, password, ns, geolocation, resolution, password_SHA256, source } = req.body;
const { user, password, ns, geolocation, resolution, password_SHA256, source, fingerprint } = req.body;

// Verify if MetaObject.Namespace have a session expiration metadata config and set
const cookieMaxAge = get(MetaObject.Namespace, 'sessionExpirationInSeconds', 2592000);
Expand All @@ -81,6 +82,7 @@ export const authApi: FastifyPluginCallback = (fastify, _, done) => {
resolution,
userAgent,
source,
fingerprint,
});

if (get(loginResult, 'success', false) === true) {
Expand Down
21 changes: 15 additions & 6 deletions src/server/routes/rest/view/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ import fp from 'fastify-plugin';

import Handlebars from 'handlebars';

import path from 'path';
import fsPromises from 'fs/promises';
import fs from 'fs';
import fsPromises from 'fs/promises';
import path from 'path';

import isDate from 'lodash/isDate';
import get from 'lodash/get';
import isDate from 'lodash/isDate';

import getServer from '@imports/utils/getServer';

import { getAuthTokenIdFromReq } from '@imports/utils/sessionUtils';
import { logout } from '@imports/auth/logout';
import { getUser } from '@imports/auth/getUser';
import { logout } from '@imports/auth/logout';
import { MetaObject } from '@imports/model/MetaObject';
import { logger } from '@imports/utils/logger';
import { getAuthTokenIdFromReq } from '@imports/utils/sessionUtils';
import { templatePath } from '@imports/utils/templatesPath';

const getEnv = () => {
Expand Down Expand Up @@ -52,6 +53,7 @@ export const viewPaths: FastifyPluginCallback = async fastify => {
lbl_browser_incompatible: 'Seu navegador não é compatível com o sistema.',
lbl_browser_install: 'Para acessar o sistema você deve instalar um dos navegadores abaixo.',
uiServer: getServer(process.env.UI_URL) || 'ui.konecty.com',
collectFingerprint: MetaObject.Namespace.trackUserFingerprint,
});

reply.header('Content-Type', 'text/html');
Expand All @@ -64,7 +66,13 @@ export const viewPaths: FastifyPluginCallback = async fastify => {
const fileStream = fs.createReadStream(loginJsFilePath);
reply.header('Content-Type', 'application/javascript');
reply.send(fileStream);
// fileStream.pipe(reply.raw);
});

fastify.get('/fp.js', function (_, reply) {
const fpJsFilePath = path.join(templatePath(), 'fingerprint.js');
const fileStream = fs.createReadStream(fpJsFilePath);
reply.header('Content-Type', 'application/javascript');
reply.send(fileStream);
});

fastify.get('/', async function (req, reply) {
Expand All @@ -89,6 +97,7 @@ export const viewPaths: FastifyPluginCallback = async fastify => {
uiServer: getServer(process.env.UI_URL) || 'ui.konecty.com',
blobUrl: process.env.BLOB_URL == null ? '' : `//${getServer(process.env.BLOB_URL)}`,
previewUrl: process.env.PREVIEW_URL == null ? '' : `//${getServer(process.env.PREVIEW_URL)}`,
collectFingerprint: MetaObject.Namespace.trackUserFingerprint,
};

const indexTemplatePath = path.join(templatePath(), 'index.hbs');
Expand Down

0 comments on commit 4b0e6f2

Please sign in to comment.