Add device fingerprint code

This commit is contained in:
Daniel Egger 2024-06-21 12:01:03 +02:00
parent e776103eb7
commit b6e4f30b58
8 changed files with 113 additions and 7 deletions

View File

@ -0,0 +1,47 @@
<template>
<div ref="scriptContainer"></div>
<noscript>
<iframe
:src="iframeSrc"
style="width: 100px; height: 100px; border: 0; position: absolute; top: -5000px"
></iframe>
</noscript>
</template>
<script>
import { ref, computed, onMounted } from "vue";
import { getLocalSessionKey } from "@/statistics";
export default {
// code needed for Datatrans/Cembra device fingerprinting
setup() {
const scriptContainer = ref(null);
const sessionId = getLocalSessionKey();
const iframeSrc = computed(() => {
return `https://h.online-metrix.net/tags?org_id=lq866c5i&session_id=${sessionId}`;
});
const insertScript = () => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = `https://h.online-metrix.net/fp/tags.js?org_id=lq866c5i&session_id=${sessionId}`;
if (scriptContainer.value) {
scriptContainer.value.appendChild(script);
}
};
onMounted(() => {
insertScript();
});
return {
scriptContainer,
iframeSrc,
};
},
};
</script>
<style scoped>
</style>

View File

@ -9,6 +9,7 @@ import type { Router } from "vue-router";
import "../tailwind.css";
import App from "./App.vue";
import router from "./router";
import { generateLocalSessionKey } from "@/statistics";
declare module "pinia" {
export interface PiniaCustomProperties {
@ -24,6 +25,8 @@ if (appEnv.startsWith("prod")) {
log.setLevel("trace");
}
generateLocalSessionKey();
const commit = "VBV_VERSION_BUILD_NUMBER_VBV";
log.warn(`application started appEnv=${appEnv}, build=${commit}`);

View File

@ -10,6 +10,8 @@ import { useRoute } from "vue-router";
import { useTranslation } from "i18next-vue";
import { getVVCourseName } from "./composables";
import ItToggleSwitch from "@/components/ui/ItToggleSwitch.vue";
import DatatransCembraDeviceFingerprint from "@/components/onboarding/DatatransCembraDeviceFingerprint.vue";
import { getLocalSessionKey } from "@/statistics";
const props = defineProps({
courseType: {
@ -178,6 +180,7 @@ const executePayment = async () => {
address: address.value,
product: props.courseType,
with_cembra_invoice: withCembraInvoice.value,
device_fingerprint_session_key: getLocalSessionKey(),
}).then((res: any) => {
console.log("Going to next page", res.next_step_url);
window.location.href = res.next_step_url;
@ -188,6 +191,7 @@ const executePayment = async () => {
<template>
<WizardPage :step="2">
<template #content>
<DatatransCembraDeviceFingerprint v-if="withCembraInvoice" />
<h2 class="my-10" data-cy="account-checkout-title">
{{ $t("a.Lehrgang kaufen") }}
</h2>

46
client/src/statistics.ts Normal file
View File

@ -0,0 +1,46 @@
let statisticsLocalSessionKey = "";
let statisticsLocalSessionRef = "";
export function uuidv4() {
// copied from https://stackoverflow.com/a/2117523/669561
// @ts-ignore
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
);
}
export function getLocalSessionKey() {
return (
window.sessionStorage.getItem("statisticsLocalSessionKey") ||
statisticsLocalSessionKey ||
""
);
}
export function generateLocalSessionKey() {
let localSessionKey =
window.sessionStorage.getItem("statisticsLocalSessionKey") ||
statisticsLocalSessionKey;
if (!localSessionKey) {
localSessionKey = uuidv4();
}
statisticsLocalSessionKey = localSessionKey;
window.sessionStorage.setItem("statisticsLocalSessionKey", localSessionKey);
return localSessionKey;
}
export function getLocalSessionRef() {
return (
window.sessionStorage.getItem("statisticsLocalSessionRef") ||
statisticsLocalSessionRef ||
""
);
}
export function setLocalSessionRef(sessionRef: string) {
if (sessionRef) {
statisticsLocalSessionRef = sessionRef;
window.sessionStorage.setItem("statisticsLocalSessionRef", sessionRef);
}
}

View File

@ -119,6 +119,8 @@ describe("checkout.cy.js", () => {
"contain",
"Lehrgang kaufen"
);
cy.get('[data-cy="cembra-switch"]').click();
cy.get("#street-address").type("Eggersmatt");
cy.get("#street-number").type("32");
cy.get("#postal-code").type("1719");
@ -127,8 +129,6 @@ describe("checkout.cy.js", () => {
cy.get("#phone").type("+41 79 201 85 86");
cy.get("#birth-date").type("1982-06-09");
cy.get('[data-cy="cembra-switch"]').click();
cy.get('[data-cy="continue-pay"]').click();
// check that results are stored on server
@ -151,6 +151,9 @@ describe("checkout.cy.js", () => {
expect(ci.product_price).to.equal(32400);
expect(ci.state).to.equal("ongoing");
expect(ci.ip_address).to.not.be.empty;
expect(ci.device_fingerprint_session_key).to.not.be.empty;
});
});
});

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.20 on 2024-06-21 08:47
# Generated by Django 3.2.20 on 2024-06-21 09:54
from django.db import migrations, models
@ -22,8 +22,8 @@ class Migration(migrations.Migration):
),
migrations.AddField(
model_name='checkoutinformation',
name='device_fingerprint',
field=models.TextField(blank=True, default=''),
name='device_fingerprint_session_key',
field=models.CharField(blank=True, default='', max_length=255),
),
migrations.AddField(
model_name='checkoutinformation',

View File

@ -83,7 +83,9 @@ class CheckoutInformation(models.Model):
birth_date = models.DateField(null=True, blank=True)
phone_number = models.CharField(max_length=255, blank=True, default="")
email = models.CharField(max_length=255, blank=True, default="")
device_fingerprint = models.TextField(blank=True, default="")
device_fingerprint_session_key = models.CharField(
max_length=255, blank=True, default=""
)
ip_address = models.CharField(max_length=255, blank=True, default="")
invoice_address = models.CharField(

View File

@ -140,7 +140,7 @@ def checkout_vv(request):
"subtype": "INVOICE",
"riskOwner": "IJ",
"repaymentType": 3,
"deviceFingerprintId": "TODO",
"deviceFingerprintId": request.data["device_fingerprint_session_key"],
}
transaction_id = init_datatrans_transaction(
user=request.user,
@ -190,6 +190,7 @@ def checkout_vv(request):
email=email,
ip_address=ip_address,
cembra_invoice=with_cembra_invoice,
device_fingerprint_session_key=request.data["device_fingerprint_session_key"],
# address
**request.data["address"],
)