Skip to content

Commit 447332b

Browse files
authored
Merge pull request #218 from hack-a-chain-software/fixes
Whitelist domains; transaction cursor; query complexity
2 parents 18e674a + a9e85b5 commit 447332b

File tree

3 files changed

+183
-19
lines changed

3 files changed

+183
-19
lines changed

indexer/src/kadena-server/repository/infra/repository/transaction-db-repository.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,18 @@ export default class TransactionDbRepository implements TransactionRepository {
148148
]);
149149

150150
const { params: txParams, conditions: txConditions } = this.createTransactionConditions(
151-
params,
151+
{ ...params, after, before },
152152
blockParams,
153153
);
154154

155155
queryParams.push(...txParams);
156156
transactionsConditions = txConditions;
157157
blocksConditions = bConditions;
158158
} else {
159-
const { conditions, params: txParams } = this.createTransactionConditions(params, [limit]);
159+
const { conditions, params: txParams } = this.createTransactionConditions(
160+
{ ...params, after, before },
161+
[limit],
162+
);
160163
const { blocksConditions: bConditions, blockParams } = this.createBlockConditions(
161164
params,
162165
txParams,

indexer/src/kadena-server/server.ts

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,13 @@ import {
3535
import { depthLimit } from '@graphile/depth-limit';
3636

3737
// Maximum allowed complexity
38-
const MAX_COMPLEXITY = 1000;
38+
const MAX_COMPLEXITY = 2500;
3939

4040
const typeDefs = readFileSync(join(__dirname, './config/schema.graphql'), 'utf-8');
4141

4242
const KADENA_GRAPHQL_API_PORT = getRequiredEnvString('KADENA_GRAPHQL_API_PORT');
4343

44-
const ALLOWED_ORIGINS = [
45-
getRequiredEnvString('API_GATEWAY_URL'),
46-
getRequiredEnvString('API_KADENA_URL'),
47-
`http://localhost:${KADENA_GRAPHQL_API_PORT}`,
48-
];
44+
const ALLOWED_ORIGINS = [process.env.API_GATEWAY_URL ?? '', process.env.API_KADENA_URL ?? ''];
4945

5046
const validatePaginationParamsPlugin: ApolloServerPlugin = {
5147
requestDidStart: async () => ({
@@ -127,13 +123,16 @@ const ipFilterMiddleware = (req: Request, res: Response, next: NextFunction) =>
127123
const isAllowedOrigin = (origin: string): boolean => {
128124
try {
129125
const originUrl = new URL(origin);
126+
if (originUrl.hostname === 'localhost') return true;
127+
130128
return ALLOWED_ORIGINS.some(allowed => {
131129
const allowedUrl = new URL(allowed);
132130
// Check if it's an exact match
133131
if (originUrl.origin === allowedUrl.origin) return true;
134132
// Check if it's a subdomain (only for kadena.io)
135-
if (allowedUrl.hostname === 'kadena.io' && originUrl.hostname.endsWith('.kadena.io'))
133+
if (allowedUrl.hostname === 'kadena.io' && originUrl.hostname.endsWith('.kadena.io')) {
136134
return true;
135+
}
137136
return false;
138137
});
139138
} catch {
@@ -233,15 +232,6 @@ export async function useKadenaGraphqlServer() {
233232
const wsServer = new WebSocketServer({
234233
server: httpServer,
235234
path: '/graphql',
236-
verifyClient: ({ origin }, callback) => {
237-
if (!origin || origin === 'null') {
238-
return callback(false, 400, 'No origin');
239-
}
240-
if (isAllowedOrigin(origin)) {
241-
return callback(true);
242-
}
243-
return callback(false, 403, 'Forbidden');
244-
},
245235
});
246236

247237
const serverCleanup = useServer(
@@ -282,14 +272,42 @@ export async function useKadenaGraphqlServer() {
282272
}
283273
},
284274
methods: ['POST', 'OPTIONS'],
285-
allowedHeaders: ['Content-Type', 'Authorization'],
275+
allowedHeaders: [
276+
'Content-Type',
277+
'Authorization',
278+
'Accept',
279+
'Origin',
280+
'X-Requested-With',
281+
'Cache-Control',
282+
'Pragma',
283+
],
284+
exposedHeaders: ['Access-Control-Allow-Origin'],
286285
credentials: true,
286+
maxAge: 86400, // 24 hours
287287
}),
288288
expressMiddleware(server, {
289289
context: createGraphqlContext,
290290
}),
291291
);
292292

293+
// Handle OPTIONS requests explicitly
294+
app.options('*', (req: Request, res: Response) => {
295+
const origin = req.headers.origin;
296+
if (origin && isAllowedOrigin(origin)) {
297+
res.setHeader('Access-Control-Allow-Origin', origin);
298+
res.setHeader('Access-Control-Allow-Credentials', 'true');
299+
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
300+
res.setHeader(
301+
'Access-Control-Allow-Headers',
302+
'Content-Type, Authorization, Accept, Origin, X-Requested-With, Cache-Control, Pragma',
303+
);
304+
res.setHeader('Access-Control-Max-Age', '86400');
305+
res.status(204).end();
306+
} else {
307+
res.status(403).end();
308+
}
309+
});
310+
293311
app.post('/new-block', ipFilterMiddleware, async (req, res) => {
294312
const payload = await dispatchInfoSchema.safeParseAsync(req.body);
295313
if (!payload.success) {

indexer/tests/integration/transactions.query.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,102 @@ const resOne = {
4646
},
4747
};
4848

49+
const resTwo = {
50+
data: {
51+
transactions: {
52+
pageInfo: {
53+
endCursor: 'MTcyNDc2MTg5',
54+
hasNextPage: false,
55+
hasPreviousPage: true,
56+
startCursor: 'MTcyNDc2MTky',
57+
},
58+
totalCount: 21,
59+
edges: [
60+
{
61+
cursor: 'MTcyNDc2MTky',
62+
node: {
63+
id: 'VHJhbnNhY3Rpb246WyJGSEQyaEVwQlltUzdDUjhsMUI2YmhyVk0zZHZLX0wxeXo5dUtLWFBBRFVRIiwicVVFdEhUZnpfOXo5cWl2dDRmZXROdHF0MDVwei15RktMdTJ3TWlHNFdyRSJd',
64+
hash: 'qUEtHTfz_9z9qivt4fetNtqt05pz-yFKLu2wMiG4WrE',
65+
cmd: {
66+
meta: {
67+
sender: 'k:b95ea3559d0bdab751891523dab34f5f57f473fdd00cb9d79a23b9414e4f4e33',
68+
},
69+
payload: {
70+
code: '"(free.radio02.add-received-with-chain \\"cc4f5cfffe205d7b\\" \\"U2FsdGVkX19SVUSGOXLII21FEVYX3X+5eqsnPJcA1PA=;;;;;oQTiyaTIRTnokdQjDZ8e6MXQyqQ5WZmgcwRJa5QmM2GngbpJCs4oG4M2Iaf0CXPxkuMplG4llknLmOwkG1CPOCVXnjoSEE+95ut7zpNwaVYTw7HJ711DJPgc1LiZEclWcKaOFRQ/Fax5t0EPnqLE5WwpGjWZEwlrdDlvx/XuJBI=\\" \\"0\\" )"',
71+
},
72+
},
73+
result: {
74+
badResult: null,
75+
goodResult: '"Write succeeded"',
76+
continuation: null,
77+
},
78+
},
79+
},
80+
{
81+
cursor: 'MTcyNDc2MTkx',
82+
node: {
83+
id: 'VHJhbnNhY3Rpb246WyJGSEQyaEVwQlltUzdDUjhsMUI2YmhyVk0zZHZLX0wxeXo5dUtLWFBBRFVRIiwiU2MweDVnWHdYVHFGd1B2LTRyUUx4VWlfYWNOa1owN3psYURsbFBfNWFzMCJd',
84+
hash: 'Sc0x5gXwXTqFwPv-4rQLxUi_acNkZ07zlaDllP_5as0',
85+
cmd: {
86+
meta: {
87+
sender: 'k:e1e4a7064bffaf7dbbf5ef5f7f3c025e5d7fe48614aa2e4d6c44ccc9dcd3d56b',
88+
},
89+
payload: {
90+
code: '"(free.radio02.close-send-receive \\"k:48e0917d48785f68572bc6506e049a713979772fa341aeb14e9ecae47d951f8c\\" [] [] )"',
91+
},
92+
},
93+
result: {
94+
badResult: null,
95+
goodResult: '""',
96+
continuation: null,
97+
},
98+
},
99+
},
100+
{
101+
cursor: 'MTcyNDc2MTkw',
102+
node: {
103+
id: 'VHJhbnNhY3Rpb246WyJGSEQyaEVwQlltUzdDUjhsMUI2YmhyVk0zZHZLX0wxeXo5dUtLWFBBRFVRIiwiV1pHdkFHQjFpVU12WENjMWRHbnc4QlZYUzJsa0NJdDhLTEN3QlRDNllVUSJd',
104+
hash: 'WZGvAGB1iUMvXCc1dGnw8BVXS2lkCIt8KLCwBTC6YUQ',
105+
cmd: {
106+
meta: {
107+
sender: 'k:6712f99b183edd481c76c1fd572b60f56620a799dd00d0a40e74a06ce1b09c77',
108+
},
109+
payload: {
110+
code: '"(free.radio02.add-received-with-chain \\"cc4f5cfffe205d7b\\" \\"U2FsdGVkX18vv0+U2aVuU/ZtRgGTo4a1ScURpWZG3Rc=;;;;;U2YBtMfdmgH65fGUlkFJdXwncaDF27GDpPBsGGVO16imgpDoJ4IHG5ZpOKxpJbV/DgsFgU/DSlfFIGIW6kIDXYcjja+icMQLZnkopKXrbOMYeNf9nEu3iOE1Gft4leAYHUqHhG9DBt9+1xOLzdxAOteuyeyhbtPb3xBK/RZilFQ=\\" \\"0\\" )"',
111+
},
112+
},
113+
result: {
114+
badResult: null,
115+
goodResult: '"Write succeeded"',
116+
continuation: null,
117+
},
118+
},
119+
},
120+
{
121+
cursor: 'MTcyNDc2MTg5',
122+
node: {
123+
id: 'VHJhbnNhY3Rpb246WyJGSEQyaEVwQlltUzdDUjhsMUI2YmhyVk0zZHZLX0wxeXo5dUtLWFBBRFVRIiwiRXQ0NWdTWGN4ZnF1bDU0Zi04TTVfaExTTjVObVYyVjhkXzVUNDlEYXlNYyJd',
124+
hash: 'Et45gSXcxfqul54f-8M5_hLSN5NmV2V8d_5T49DayMc',
125+
cmd: {
126+
meta: {
127+
sender: 'k:0e98a32914e0af5c3dc2b41f216a37091d1664b00b6a8e3a87d5e5022eeab4e3',
128+
},
129+
payload: {
130+
code: '"(free.radio02.direct-to-send \\"k:b3c65463af1f398a5465c15c4c9f221d3a5bb3efad52829715f088a7ee4bc7d3\\" )"',
131+
},
132+
},
133+
result: {
134+
badResult: null,
135+
goodResult: '"Write succeeded"',
136+
continuation: null,
137+
},
138+
},
139+
},
140+
],
141+
},
142+
},
143+
};
144+
49145
describe('Transactions Query', () => {
50146
it('blockHash: "Qzi58vcpW97du01srIwxpwSQUPDRNBnl2EKyubP-IWw"', async () => {
51147
const query = gql`
@@ -84,4 +180,51 @@ describe('Transactions Query', () => {
84180
const data = await client.request(query);
85181
expect(resOne.data).toMatchObject(data);
86182
});
183+
184+
it('first: "20", after: "MTcyNDc2MTkz", blockHash: "FHD2hEpBYmS7CR8l1B6bhrVM3dvK_L1yz9uKKXPADUQ"', async () => {
185+
const query = gql`
186+
query {
187+
transactions(
188+
first: 20
189+
after: "MTcyNDc2MTkz"
190+
blockHash: "FHD2hEpBYmS7CR8l1B6bhrVM3dvK_L1yz9uKKXPADUQ"
191+
) {
192+
pageInfo {
193+
endCursor
194+
hasNextPage
195+
hasPreviousPage
196+
startCursor
197+
}
198+
totalCount
199+
edges {
200+
cursor
201+
node {
202+
id
203+
hash
204+
cmd {
205+
meta {
206+
sender
207+
}
208+
payload {
209+
... on ExecutionPayload {
210+
code
211+
}
212+
}
213+
}
214+
result {
215+
... on TransactionResult {
216+
badResult
217+
goodResult
218+
continuation
219+
}
220+
}
221+
}
222+
}
223+
}
224+
}
225+
`;
226+
227+
const data = await client.request(query);
228+
expect(resTwo.data).toMatchObject(data);
229+
});
87230
});

0 commit comments

Comments
 (0)