This commit is contained in:
seb
2026-09-29 11:21:55 +02:00
parent 3089cc7252
commit cf4af1480b
7 changed files with 173 additions and 0 deletions

9
src/v1/index.js Normal file
View File

@@ -0,0 +1,9 @@
import { Router } from 'express';
import { handleClient } from './routes/client.js';
const router = Router();
// POS discovery and pairing
router.get('/client', handleClient);
export default router;

126
src/v1/routes/client.js Normal file
View File

@@ -0,0 +1,126 @@
import crypto from 'node:crypto';
import * as db from '../../db/posterminal.js';
import { getCompanyById } from '../../db/company.js';
import { getCertMetadata } from '../../util/cert.js';
export function serverTimestamp() {
const d = new Date();
const pad = (n) => String(n).padStart(2, '0');
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
export function buildClientStep1(config) {
const {
certificateFingerprint,
certificateSerialNumber,
mandantId,
serverFingerprint,
} = config;
return {
authCode: null,
authToken: null,
certificateFingerprint,
certificateSerialNumber,
mandantId,
mandantName: null,
mandantDatabase: null,
serverFingerprint,
name: null,
serverTimestamp: serverTimestamp(),
};
}
export function buildClientStep2(authCode, config) {
const {
authToken,
certificateFingerprint,
certificateSerialNumber,
mandantId,
mandantName,
mandantDatabase,
} = config;
return {
authCode,
authToken,
certificateFingerprint,
certificateSerialNumber,
mandantId,
mandantName,
mandantDatabase,
serverFingerprint: null,
name: null,
serverTimestamp: serverTimestamp(),
};
}
/**
* Handles GET /v1/client
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
export async function handleClient(req, res) {
const authCode = String(req.query.authCode || '').trim();
const name = String(req.query.name || 'JTL-POS').trim();
try {
const certMeta = await getCertMetadata();
if (authCode.length <= 4 && authCode.length > 0) {
const config = {
...certMeta,
mandantId: process.env.MANDANT_ID || '1',
};
return res.status(200).json(buildClientStep1(config));
}
if (authCode.length === 6) {
const terminal = await db.findByPairingpin(authCode);
if (terminal) {
const token = terminal.token;
const strToken = String(token || crypto.randomBytes(16).toString('hex')).trim();
const pairedAt = serverTimestamp();
await db.pair(terminal.id, {
token: strToken,
clientserial: name,
pairedAt,
});
let mandantName = process.env.MANDANT_NAME || 'eB-Standard';
let mandantDatabase = process.env.MANDANT_DATABASE || 'eazybusiness';
let mandantId = String(terminal.companyId || process.env.MANDANT_ID || '1');
if (terminal.companyId) {
try {
const company = await getCompanyById(terminal.companyId);
if (company) {
mandantName = company.name;
mandantDatabase = company.name;
}
} catch {
// ignore lookup error and fallback to defaults
}
}
const config = {
...certMeta,
authToken: strToken,
mandantId,
mandantName,
mandantDatabase,
};
return res.status(200).json(buildClientStep2(authCode, config));
}
return res.status(400).json({ Message: 'Der Authentifizierungscode ist falsch.' });
}
return res.status(400).json({ Message: 'Keinen passenden Authentifizierungscode gefunden.' });
} catch (err) {
console.error('POS /v1/client error:', err);
return res.status(500).json({ Message: 'Internal server error' });
}
}