Add device fingerprint code
This commit is contained in:
parent
e776103eb7
commit
b6e4f30b58
|
|
@ -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>
|
||||||
|
|
@ -9,6 +9,7 @@ import type { Router } from "vue-router";
|
||||||
import "../tailwind.css";
|
import "../tailwind.css";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
|
import { generateLocalSessionKey } from "@/statistics";
|
||||||
|
|
||||||
declare module "pinia" {
|
declare module "pinia" {
|
||||||
export interface PiniaCustomProperties {
|
export interface PiniaCustomProperties {
|
||||||
|
|
@ -24,6 +25,8 @@ if (appEnv.startsWith("prod")) {
|
||||||
log.setLevel("trace");
|
log.setLevel("trace");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateLocalSessionKey();
|
||||||
|
|
||||||
const commit = "VBV_VERSION_BUILD_NUMBER_VBV";
|
const commit = "VBV_VERSION_BUILD_NUMBER_VBV";
|
||||||
log.warn(`application started appEnv=${appEnv}, build=${commit}`);
|
log.warn(`application started appEnv=${appEnv}, build=${commit}`);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import { useRoute } from "vue-router";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
import { getVVCourseName } from "./composables";
|
import { getVVCourseName } from "./composables";
|
||||||
import ItToggleSwitch from "@/components/ui/ItToggleSwitch.vue";
|
import ItToggleSwitch from "@/components/ui/ItToggleSwitch.vue";
|
||||||
|
import DatatransCembraDeviceFingerprint from "@/components/onboarding/DatatransCembraDeviceFingerprint.vue";
|
||||||
|
import { getLocalSessionKey } from "@/statistics";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
courseType: {
|
courseType: {
|
||||||
|
|
@ -178,6 +180,7 @@ const executePayment = async () => {
|
||||||
address: address.value,
|
address: address.value,
|
||||||
product: props.courseType,
|
product: props.courseType,
|
||||||
with_cembra_invoice: withCembraInvoice.value,
|
with_cembra_invoice: withCembraInvoice.value,
|
||||||
|
device_fingerprint_session_key: getLocalSessionKey(),
|
||||||
}).then((res: any) => {
|
}).then((res: any) => {
|
||||||
console.log("Going to next page", res.next_step_url);
|
console.log("Going to next page", res.next_step_url);
|
||||||
window.location.href = res.next_step_url;
|
window.location.href = res.next_step_url;
|
||||||
|
|
@ -188,6 +191,7 @@ const executePayment = async () => {
|
||||||
<template>
|
<template>
|
||||||
<WizardPage :step="2">
|
<WizardPage :step="2">
|
||||||
<template #content>
|
<template #content>
|
||||||
|
<DatatransCembraDeviceFingerprint v-if="withCembraInvoice" />
|
||||||
<h2 class="my-10" data-cy="account-checkout-title">
|
<h2 class="my-10" data-cy="account-checkout-title">
|
||||||
{{ $t("a.Lehrgang kaufen") }}
|
{{ $t("a.Lehrgang kaufen") }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -119,6 +119,8 @@ describe("checkout.cy.js", () => {
|
||||||
"contain",
|
"contain",
|
||||||
"Lehrgang kaufen"
|
"Lehrgang kaufen"
|
||||||
);
|
);
|
||||||
|
cy.get('[data-cy="cembra-switch"]').click();
|
||||||
|
|
||||||
cy.get("#street-address").type("Eggersmatt");
|
cy.get("#street-address").type("Eggersmatt");
|
||||||
cy.get("#street-number").type("32");
|
cy.get("#street-number").type("32");
|
||||||
cy.get("#postal-code").type("1719");
|
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("#phone").type("+41 79 201 85 86");
|
||||||
cy.get("#birth-date").type("1982-06-09");
|
cy.get("#birth-date").type("1982-06-09");
|
||||||
|
|
||||||
cy.get('[data-cy="cembra-switch"]').click();
|
|
||||||
|
|
||||||
cy.get('[data-cy="continue-pay"]').click();
|
cy.get('[data-cy="continue-pay"]').click();
|
||||||
|
|
||||||
// check that results are stored on server
|
// check that results are stored on server
|
||||||
|
|
@ -151,6 +151,9 @@ describe("checkout.cy.js", () => {
|
||||||
expect(ci.product_price).to.equal(32400);
|
expect(ci.product_price).to.equal(32400);
|
||||||
|
|
||||||
expect(ci.state).to.equal("ongoing");
|
expect(ci.state).to.equal("ongoing");
|
||||||
|
|
||||||
|
expect(ci.ip_address).to.not.be.empty;
|
||||||
|
expect(ci.device_fingerprint_session_key).to.not.be.empty;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
@ -22,8 +22,8 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='checkoutinformation',
|
model_name='checkoutinformation',
|
||||||
name='device_fingerprint',
|
name='device_fingerprint_session_key',
|
||||||
field=models.TextField(blank=True, default=''),
|
field=models.CharField(blank=True, default='', max_length=255),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='checkoutinformation',
|
model_name='checkoutinformation',
|
||||||
|
|
@ -83,7 +83,9 @@ class CheckoutInformation(models.Model):
|
||||||
birth_date = models.DateField(null=True, blank=True)
|
birth_date = models.DateField(null=True, blank=True)
|
||||||
phone_number = models.CharField(max_length=255, blank=True, default="")
|
phone_number = models.CharField(max_length=255, blank=True, default="")
|
||||||
email = 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="")
|
ip_address = models.CharField(max_length=255, blank=True, default="")
|
||||||
|
|
||||||
invoice_address = models.CharField(
|
invoice_address = models.CharField(
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ def checkout_vv(request):
|
||||||
"subtype": "INVOICE",
|
"subtype": "INVOICE",
|
||||||
"riskOwner": "IJ",
|
"riskOwner": "IJ",
|
||||||
"repaymentType": 3,
|
"repaymentType": 3,
|
||||||
"deviceFingerprintId": "TODO",
|
"deviceFingerprintId": request.data["device_fingerprint_session_key"],
|
||||||
}
|
}
|
||||||
transaction_id = init_datatrans_transaction(
|
transaction_id = init_datatrans_transaction(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
|
|
@ -190,6 +190,7 @@ def checkout_vv(request):
|
||||||
email=email,
|
email=email,
|
||||||
ip_address=ip_address,
|
ip_address=ip_address,
|
||||||
cembra_invoice=with_cembra_invoice,
|
cembra_invoice=with_cembra_invoice,
|
||||||
|
device_fingerprint_session_key=request.data["device_fingerprint_session_key"],
|
||||||
# address
|
# address
|
||||||
**request.data["address"],
|
**request.data["address"],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue