@emaraplay/nobles 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emaraplay/nobles",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "mocha test --recursive --timeout 5000 --reporter mochawesome --exit",
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const errors = [];
8
+
9
+ function validateFile(filePath) {
10
+ const content = fs.readFileSync(filePath, 'utf8');
11
+ const dir = path.dirname(filePath);
12
+
13
+ const requireRegex = /require\(['"](\.[^'"]+)['"]\)/g;
14
+ let match;
15
+
16
+ while ((match = requireRegex.exec(content)) !== null) {
17
+ const requirePath = match[1];
18
+
19
+ let fullPath = path.join(dir, requirePath);
20
+
21
+ const extensions = ['', '.js', '.json', '/index.js'];
22
+ let found = false;
23
+ let actualPath = null;
24
+
25
+ for (const ext of extensions) {
26
+ const testPath = fullPath + ext;
27
+ if (fs.existsSync(testPath)) {
28
+ actualPath = testPath;
29
+ found = true;
30
+ break;
31
+ }
32
+ }
33
+
34
+ if (!found) {
35
+ errors.push({
36
+ file: filePath,
37
+ require: requirePath,
38
+ error: 'File not found'
39
+ });
40
+ continue;
41
+ }
42
+
43
+ const expectedName = path.basename(actualPath);
44
+ const actualFiles = fs.readdirSync(path.dirname(actualPath));
45
+
46
+ if (!actualFiles.includes(expectedName)) {
47
+ const realFile = actualFiles.find(f => f.toLowerCase() === expectedName.toLowerCase());
48
+
49
+ if (realFile && realFile !== expectedName) {
50
+ errors.push({
51
+ file: filePath,
52
+ require: requirePath,
53
+ expected: expectedName,
54
+ actual: realFile,
55
+ error: 'Case mismatch (will fail on Linux)'
56
+ });
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ function scanDirectory(dir) {
63
+ const items = fs.readdirSync(dir);
64
+
65
+ for (const item of items) {
66
+ const fullPath = path.join(dir, item);
67
+ const stat = fs.statSync(fullPath);
68
+
69
+ if (stat.isDirectory() && item !== 'node_modules' && item !== '.git') {
70
+ scanDirectory(fullPath);
71
+ } else if (stat.isFile() && item.endsWith('.js')) {
72
+ validateFile(fullPath);
73
+ }
74
+ }
75
+ }
76
+
77
+ const srcPath = path.join(__dirname, '..', 'src');
78
+ console.log('🔍 Validando imports en:', srcPath);
79
+ scanDirectory(srcPath);
80
+
81
+ if (errors.length > 0) {
82
+ console.error('\n❌ Se encontraron errores de case-sensitivity:\n');
83
+ errors.forEach(err => {
84
+ console.error(`📁 ${err.file}`);
85
+ console.error(` require: ${err.require}`);
86
+ if (err.expected && err.actual) {
87
+ console.error(` ❌ Esperado: ${err.expected}`);
88
+ console.error(` ✅ Real: ${err.actual}`);
89
+ }
90
+ console.error(` Error: ${err.error}\n`);
91
+ });
92
+ process.exit(1);
93
+ } else {
94
+ console.log('✅ Todos los imports son correctos\n');
95
+ process.exit(0);
96
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const dayjs = require('dayjs');
4
4
  const got = require('got');
5
+ const { getHMAC } = require('../utils/sign.helper');
5
6
 
6
7
  function mapCategoryToEnum(category) {
7
8
  if (typeof category !== 'string') return undefined;
@@ -82,13 +83,12 @@ async function getGames(provider) {
82
83
  }
83
84
 
84
85
  const endpoint = provider.urls.gameList;
85
- if (!endpoint) {
86
- throw new Error('Proveedor sin endpoint de lista de juegos configurado');
87
- }
88
-
86
+ const operator = {operatorCode: provider.params.k2};
87
+ const sign = getHMAC(operator, provider.params.k1);
89
88
  const response = await got.get(endpoint, {
90
89
  responseType: 'json',
91
90
  headers: {
91
+ 'x-request-sign': sign,
92
92
  'Content-Type': 'application/json'
93
93
  }
94
94
  });
@@ -103,33 +103,33 @@ async function getGames(provider) {
103
103
 
104
104
  for (const game of gamesData) {
105
105
  try {
106
- if (!game.gameMode || !game.title) {
106
+ if (!game.code || !game.name) {
107
107
  skippedGamesCount++;
108
108
  continue;
109
109
  }
110
110
 
111
111
  const gameType = mapCategoryToEnum(game.category) || 'OTHER';
112
112
 
113
- const hasFreespins = Array.isArray(game.bonusTypes) && game.bonusTypes.length > 0;
114
113
 
115
114
  const gameData = {
116
- alias: game.gameMode,
117
- name: game.title.trim(),
118
- freespins: hasFreespins,
119
- fun: true,
115
+ alias: game.code,
116
+ name: game.name.trim(),
117
+ freespins: game.promoFeatures?.freespins || false,
118
+ fun: game.promoFeatures?.demo || true,
120
119
  type: gameType,
121
120
  platform: {
122
- mobile: true,
121
+ mobile: game.mobileHorizontalStatus || false,
123
122
  desktop: true,
124
123
  },
124
+ liveGame: game.isLive || false,
125
125
  params: {
126
- description: game.description || '',
126
+ betLevels: game.betLevels || [],
127
127
  multiplayer: game.multiplayer || false
128
128
  }
129
129
  };
130
130
 
131
- if (game.rtp) {
132
- const rtpVal = Number(game.rtp);
131
+ if (game.parameters?.rtp) {
132
+ const rtpVal = Number(game.parameters.rtp);
133
133
  if (!Number.isNaN(rtpVal)) {
134
134
  const normalizedRtp = rtpVal <= 1 ? rtpVal * 100 : rtpVal;
135
135
  if (normalizedRtp > 0 && normalizedRtp <= 100) {
@@ -137,8 +137,16 @@ async function getGames(provider) {
137
137
  }
138
138
  }
139
139
  }
140
-
141
- gameData.launchDate = dayjs().toDate();
140
+ if (game.releaseDate) {
141
+ const releaseDate = dayjs(game.releaseDate);
142
+ if (releaseDate.isValid()) {
143
+ gameData.launchDate = releaseDate.toDate();
144
+ } else {
145
+ gameData.launchDate = dayjs().toDate();
146
+ }
147
+ } else {
148
+ gameData.launchDate = dayjs().toDate();
149
+ }
142
150
 
143
151
  processedGames.push(gameData);
144
152
  } catch (gameError) {
@@ -153,7 +161,7 @@ async function getGames(provider) {
153
161
 
154
162
  return processedGames;
155
163
  } catch (error) {
156
- console.error('Error obteniendo juegos de InOut desde API:', error.message);
164
+ console.error('Error obteniendo juegos de Nobles desde API:', error.message);
157
165
  throw error;
158
166
  }
159
167
  }
@@ -4,15 +4,7 @@ const xss = require('xss');
4
4
  const crypto = require('crypto');
5
5
  const got = require('got');
6
6
  const { getHMAC } = require('../utils/sign.helper');
7
-
8
- function sortPlainObjectKeysAsc(obj) {
9
- const sortedKeys = Object.keys(obj).sort();
10
- const sortedObj = {};
11
- for (const key of sortedKeys) {
12
- sortedObj[key] = obj[key];
13
- }
14
- return sortedObj;
15
- }
7
+ const { sortPlainObjetKeysAsc } = require('../utils');
16
8
 
17
9
  module.exports = async function(request, provider, aUser, game, sessionId, mode) {
18
10
  try {
@@ -20,14 +12,14 @@ module.exports = async function(request, provider, aUser, game, sessionId, mode)
20
12
  if (!launchUrl) throw new Error('URL de lanzamiento (launcher) no configurada para el proveedor.');
21
13
  const operatorId = provider?.k2;
22
14
  if (!operatorId) throw new Error('operatorId (k2) no configurado para el proveedor.');
23
- const gameMode = game?.a;
24
- if (!gameMode) throw new Error('El ID del juego (game.a) es inválido.');
15
+ const gameCode = game?.a;
16
+ if (!gameCode) throw new Error('El ID del juego (game.a) es inválido.');
25
17
 
26
18
  const lng = xss(request.data?.lang || aUser?.data?.language || request.body?.lang || 'es-ES');
27
19
  const lobbyUrl = xss(request.query.lobby) || xss(request.bookmaker?.url?.l);
28
20
  const callbackUrl = xss(provider.params?.callBack) || lobbyUrl;
29
21
  const isDemo = mode === 'fun' || mode === 'demo';
30
- const user = isDemo ? 'DemoUser' : String(aUser?.data?.internal || '');
22
+ const user = isDemo ? `DemoUser-${crypto.randomBytes(8).toString('hex')}` : String(aUser?.data?.internal || '');
31
23
  const balance = isDemo ? 10000 : (aUser?.data?.balance || 0);
32
24
  const currency = isDemo ? 'USD' : xss(aUser?.data?.currency || 'ARS');
33
25
  let demoUrl;
@@ -37,7 +29,7 @@ module.exports = async function(request, provider, aUser, game, sessionId, mode)
37
29
  demoUrl = `${provider.urls.baseUrl}/demo/sessions`;
38
30
  const demoAuthToken = crypto.randomBytes(16).toString('hex');
39
31
  body = {
40
- gameCode: gameMode,
32
+ gameCode,
41
33
  playerId: user,
42
34
  operatorCode: operatorId,
43
35
  callbackUrl: callbackUrl,
@@ -49,7 +41,7 @@ module.exports = async function(request, provider, aUser, game, sessionId, mode)
49
41
  };
50
42
  } else {
51
43
  body = {
52
- gameCode: gameMode,
44
+ gameCode,
53
45
  playerId: user,
54
46
  operatorCode: operatorId,
55
47
  callbackUrl: callbackUrl,
@@ -62,7 +54,7 @@ module.exports = async function(request, provider, aUser, game, sessionId, mode)
62
54
 
63
55
  }
64
56
 
65
- const sortedBody = sortPlainObjectKeysAsc(body);
57
+ const sortedBody = sortPlainObjetKeysAsc(body);
66
58
  const signature = getHMAC(sortedBody, provider.k1);
67
59
 
68
60
  const response = await got.post(isDemo ? demoUrl : launchUrl, {
@@ -3,3 +3,4 @@ module.exports.getError = require('./error.helper');
3
3
  module.exports.constants = require('./constants');
4
4
  module.exports.security = require('./sign.helper');
5
5
  module.exports.currencyHelper = require('./currency.helper');
6
+ module.exports.sortPlainObjetKeysAsc = require('./sortPlainObjetKeysAsc.helper');
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ module.exports = (obj) => {
4
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return obj;
5
+
6
+ const sortedKeys = Object.keys(obj).sort();
7
+ const sortedObj = {};
8
+
9
+ for (const key of sortedKeys) {
10
+ sortedObj[key] = obj[key];
11
+ }
12
+
13
+ return sortedObj;
14
+ };
@@ -6,6 +6,7 @@ const utils = require('@emaraplay/utils');
6
6
  const { ERRORS, buildHttpError } = require('../utils/error.helper');
7
7
  const { isValidSign } = require('../utils/sign.helper');
8
8
  const { currencyHelper } = require('../utils/currency.helper');
9
+ const { sortPlainObjetKeysAsc } = require('../utils');
9
10
 
10
11
  const validateAuthenticateRequest = (params) => {
11
12
  if (!params.user) return buildHttpError(ERRORS.INVALID_USER.error);
@@ -17,7 +18,7 @@ module.exports = async function(controller, fastify, request) {
17
18
  try {
18
19
  const signature = request.headers['x-request-sign'];
19
20
  if (!signature) return buildHttpError(ERRORS.MISSING_SIGNATURE.error);
20
- const query = JSON.stringify(request.query);
21
+ const query = sortPlainObjetKeysAsc(request.query);
21
22
  const secretKey = request.provider.k1;
22
23
  if (!isValidSign(signature, query, secretKey)) {
23
24
  return buildHttpError(ERRORS.INVALID_HASH.error);
@@ -5,6 +5,7 @@ const { ERRORS, buildHttpError } = require('../utils/error.helper');
5
5
  const { normalize } = require('../utils');
6
6
  const { isValidSign } = require('../utils/sign.helper');
7
7
  const { currencyHelper } = require('../utils/currency.helper');
8
+ const { sortPlainObjetKeysAsc } = require('../utils');
8
9
  const utils = require('@emaraplay/utils');
9
10
 
10
11
  const validateBetRequest = (params) => {
@@ -27,7 +28,8 @@ module.exports = async function (controller, fastify, request) {
27
28
  return buildHttpError(ERRORS.MISSING_SIGNATURE.error);
28
29
  }
29
30
  const secretKey = request.provider.k1;
30
- if (!isValidSign(signature, request.rawBody, secretKey)) {
31
+ const sortedBody = sortPlainObjetKeysAsc(request.body);
32
+ if (!isValidSign(signature, sortedBody, secretKey)) {
31
33
  return buildHttpError(ERRORS.INVALID_HASH.error)
32
34
  }
33
35
  const body = normalize(request.body, request);
@@ -4,7 +4,8 @@ const Sentry = require('@sentry/node');
4
4
  const { ERRORS, buildHttpError } = require('../utils/error.helper');
5
5
  const { normalize } = require('../utils');
6
6
  const { isValidSign } = require('../utils/sign.helper');
7
- const { currencyHelper } = require('../utils/currency.helper');
7
+ const { currencyHelper } = require('../utils/currency.helper');
8
+ const { sortPlainObjetKeysAsc } = require('../utils');
8
9
  const utils = require('@emaraplay/utils');
9
10
 
10
11
  const validateRollbackRequest = (params) => {
@@ -32,7 +33,8 @@ module.exports = async function (controller, fastify, request) {
32
33
  }
33
34
 
34
35
  if (!signature) return buildHttpError(ERRORS.MISSING_SIGNATURE.error);
35
- if (!isValidSign(signature, request.rawBody, secretKey)) {
36
+ const sortedBody = sortPlainObjetKeysAsc(request.body);
37
+ if (!isValidSign(signature, sortedBody, secretKey)) {
36
38
  return buildHttpError(ERRORS.INVALID_HASH.error);
37
39
  }
38
40