Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions plugins/asphyxia-core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,15 @@ declare namespace U {
* @param encoding see [[KEncoding]]
*/
function DecodeString(buffer: Buffer, encoding: KEncoding): string;

/**
* Allow to set a token for cardless authentication.
*
* returns a string
* @param token token to set.
* @param refid refid of the profile to set token for.
*/
function SetSPPassToken(token: string, refid: string): void;
}

/** @ignore */
Expand Down
89 changes: 89 additions & 0 deletions src/eamuse/Core/SPPass.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { EamuseRouteContainer } from '../EamuseRouteContainer';
import { get } from 'lodash';
import { Logger } from '../../utils/Logger';
import { kitem } from '../../utils/KBinJSON';
import { FindCardsByRefid } from '../../utils/EamuseIO';


export const sppass = new EamuseRouteContainer();

const sppassTokens: { [token: string]: {date: Date, refid: string} } = {};

sppass.add('sppass.open', async (info, data, send) => {
cleanUpTokens();

const token = randomToken(4);
sppassTokens[token] = {date: new Date(Date.now() + 60000), refid: ""}; // +1 minute expiry

Logger.debug(`SPPass Opened: ${token}`);

send.object({
token: kitem('str', token),
expire_datetime: kitem('str', new Date().toISOString().slice(0, 19).replace('T', ' ')), // Format: 2026-05-14 08:09:35
url: kitem('str', token),
interval: kitem('s32', 2),
});
});

sppass.add('sppass.lookup', async (info, data, send) => {
Logger.debug(`info: ${JSON.stringify(info)}, data: ${JSON.stringify(data)}`);


const token: string = get(data, '@attr.token');

let card_id = "";
let card_type = "";
if (sppassTokens[token]) {
let card = await FindCardsByRefid(sppassTokens[token].refid);
if (card && card.length > 0) {
card_id = card[0].cid;
card_type = "1";
}
}
Logger.debug(`SPPass Lookup: ${token} -> ${card_id}`);

send.object({
url: kitem('str', token),
interval: kitem('s32', 2),
card_type: kitem('str', card_type),
card_id: kitem('str', card_id),
});

// Release token after lookup if card_id is set
if (card_id) {
delete sppassTokens[token];
Logger.debug(`SPPass Token Released: ${token}`);
}
});

export function setSPPassToken(token: string, refid: string) {
Logger.debug(JSON.stringify(sppassTokens, null, 4));

if (sppassTokens[token] !== undefined) {
sppassTokens[token].refid = refid;
Logger.debug(`SPPass Token Set: ${token} -> ${refid}`);
} else {
Logger.warn(`SPPass Token Not Found: ${token}`);
}
}

function cleanUpTokens() {
const now = new Date();
for (const token in sppassTokens) {
if (sppassTokens[token].date < now) {
delete sppassTokens[token];
Logger.debug(`SPPass Token Expired: ${token}`);
}
}
}

function randomToken(length: number): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';

for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}

return result;
}
4 changes: 4 additions & 0 deletions src/eamuse/Core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { cardmng } from './CardManager';
import { eacoin } from './EamuseCoin';
import { facility } from './Facility';
import { pcbtracker } from './PCBTracker';
import { sppass} from './SPPass';

import { kitem } from '../../utils/KBinJSON';
import { EamuseRouteContainer } from '../EamuseRouteContainer';
import { Logger } from '../../utils/Logger';
import { CONFIG } from '../../utils/ArgConfig';


export const core = new EamuseRouteContainer();

core.add('message.get', async (info, data, send) => {
Expand Down Expand Up @@ -66,3 +69,4 @@ core.add(eacoin);
core.add(facility);
core.add(cardmng);
core.add(pcbtracker);
core.add(sppass);
1 change: 1 addition & 0 deletions src/eamuse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const services = (port: number, plugins: EamusePlugin[]) => {
'netlog',
'sidmgr',
'globby',
'sppass'
];

/* General Information */
Expand Down
36 changes: 29 additions & 7 deletions src/middlewares/EamuseMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,23 +113,45 @@ export const EamuseMiddleware: RequestHandler = async (req, res, next) => {
return;
}

const eaModule = findKey(
let eaModule = findKey(
get(xml, 'call'),
x => has(x, '@attr.method') || has(x, '0.@attr.method')
);
)

if (eaModule === undefined && req.url.includes("fnc")) {
eaModule = "sppass";
Logger.debug(`${req.url}`)
}

if (!eaModule) {
res.sendStatus(404);
return;
}

let moduleObj: any[] = get(xml, `call.${eaModule}`, null);
if (!isArray(moduleObj)) moduleObj = [moduleObj];
let eaMethod = undefined;
let model = undefined;
let token = undefined;

if (eaModule !== 'sppass') {
let moduleObj: any[] = get(xml, `call.${eaModule}`, null);
if (!isArray(moduleObj)) moduleObj = [moduleObj];

const eaMethods: string[] = moduleObj.map(x => get(x, `@attr.method`));
const eaMethod = eaMethods.join('.');
const model = get(xml, 'call.@attr.model');
const eaMethods: string[] = moduleObj.map(x => get(x, `@attr.method`));
eaMethod = eaMethods.join('.');
model = get(xml, 'call.@attr.model');
} else {
const urlParams = new URLSearchParams(req.url.split('?')[1]);
eaMethod = urlParams.get('fnc');
model = urlParams.get('sic');

// Since SPPass doesn't send XML data, we need to get token from URL parameters and construct a fake XML data for further processing.
token = { call: { sppass: { "@attr": { token: urlParams.get('token') || "" } } } };

// rewind url encoding
model = decodeURIComponent(model || '');
xml = token;
}

if (!(process as any).pkg) {
Logger.debug(`${eaModule}.${eaMethod}\n${dataToXML(xml, false)}`);
}
Expand Down
Loading