Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ GraphQL Analyzer includes advanced security testing for:

## ⚙️ Requirements

- **Caido** v0.51.2 or higher
- **Caido** v0.57.0 or higher


## 🤝 Contributing
Expand Down
66 changes: 33 additions & 33 deletions caido.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { defineConfig } from '@caido-community/dev';
import vue from '@vitejs/plugin-vue';
import path from "path";

import tailwindCaido from "@caido/tailwindcss";
import { defineConfig } from "@caido-community/dev";
import vue from "@vitejs/plugin-vue";
import prefixwrap from "postcss-prefixwrap";
import tailwindcss from "tailwindcss";
// @ts-expect-error no declared types at this time
import tailwindPrimeui from "tailwindcss-primeui";
import tailwindCaido from "@caido/tailwindcss";
import path from "path";
import prefixwrap from "postcss-prefixwrap";

const id = "graphql-analyzer";
export default defineConfig({
id,
name: "GraphQL Analyzer",
description: "Plugin for GraphQL schema discovery, visualization, and advanced security",
version: "1.0.4",
description:
"Plugin for GraphQL schema discovery, visualization, and advanced security",
version: "1.0.5",
author: {
name: "Amr Elsagaei",
email: "info@amrelsagaei.com",
Expand All @@ -25,9 +27,9 @@ export default defineConfig({
root: "packages/backend",
},
{
kind: 'frontend',
kind: "frontend",
id: "frontend",
root: 'packages/frontend',
root: "packages/frontend",
backend: {
id: "backend",
},
Expand All @@ -36,21 +38,20 @@ export default defineConfig({
build: {
rollupOptions: {
external: [
'@caido/frontend-sdk',
"@codemirror/autocomplete",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@caido/frontend-sdk",
"@codemirror/autocomplete",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
"vue",

]
}
],
},
},
resolve: {
alias: [
Expand All @@ -72,25 +73,24 @@ export default defineConfig({
preflight: false,
},
content: [
'./packages/frontend/src/**/*.{vue,ts}',
'./node_modules/@caido/primevue/dist/primevue.mjs'
"./packages/frontend/src/**/*.{vue,ts}",
"./node_modules/@caido/primevue/dist/primevue.mjs",
],
// Check the [data-mode="dark"] attribute on the <html> element to determine the mode
// This attribute is set in the Caido core application
darkMode: ["selector", '[data-mode="dark"]'],
plugins: [

// This plugin injects the necessary Tailwind classes for PrimeVue components
tailwindPrimeui,

// This plugin injects the necessary Tailwind classes for the Caido theme
tailwindCaido,
],
})
]
}
}
}
}
]
});
}),
],
},
},
},
},
],
});
2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"zod": "4.3.6"
},
"devDependencies": {
"@caido/sdk-backend": "^0.51.0"
"@caido/sdk-backend": "0.57.0"
}
}
2 changes: 1 addition & 1 deletion packages/backend/src/services/graphql/client.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { SDK } from "caido:plugin";
import { RequestSpec } from "caido:utils";
import type { GraphQLSchema, Result } from "shared";
import { INTROSPECTION_QUERY } from "shared";

import { INTROSPECTION_QUERY } from "./introspection";
import {
mapHttpStatusToError,
mergeHeaders,
Expand Down
89 changes: 0 additions & 89 deletions packages/backend/src/services/graphql/introspection.ts

This file was deleted.

9 changes: 6 additions & 3 deletions packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@
"@caido/primevue": "0.1.2",
"@codemirror/lang-javascript": "6.2.1",
"@codemirror/lang-json": "6.0.1",
"@codemirror/language": "6.11.3",
"@codemirror/state": "6.4.1",
"@codemirror/theme-one-dark": "6.1.2",
"@codemirror/view": "6.28.1",
"@tanstack/vue-virtual": "3.13.18",
"@vueuse/core": "10.5.0",
"codemirror": "6.0.1",
"primevue": "4.1.0",
"vue": "3.4.37"
"ts-http-forge": "0.1.7",
"vue": "3.4.37",
"zod": "4.3.6"
},
"devDependencies": {
"@caido/sdk-backend": "^0.51.0",
"@caido/sdk-frontend": "^0.51.2-beta.0",
"@caido/sdk-backend": "0.57.0",
"@caido/sdk-frontend": "0.57.1-beta.6",
"backend": "workspace:*",
"shared": "workspace:*",
"vue-tsc": "2.0.29"
Expand Down
56 changes: 20 additions & 36 deletions packages/frontend/src/components/attacks/Container.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1375,45 +1375,29 @@ const createFindingFromResult = async (result: AttackResult) => {
};

const sendToReplay = async (result: AttackResult) => {
try {
if (result.rawRequest === undefined || result.rawRequest === "") {
sdk.window.showToast("No request data available for replay", {
variant: "error",
});
return;
}

let domain = "Unknown";
try {
if (result.targetUrl) {
const url = new URL(result.targetUrl);
domain = url.hostname;
}
} catch (error) {
domain = "Unknown";
}
if (result.rawRequest === undefined || result.rawRequest === "") {
sdk.window.showToast("No request data available for replay", {
variant: "error",
});
return;
}

const replayResult = await replayService.createReplayFromRequest(
result.rawRequest,
domain,
);
const replayResult = await replayService.createReplayFromRequest(
result.rawRequest,
result.targetUrl,
);

if (replayResult.kind === "Ok") {
sdk.window.showToast(
`Created replay session: ${replayResult.value.sessionName}`,
{ variant: "success" },
);
} else {
sdk.window.showToast(`Failed to create replay: ${replayResult.error}`, {
variant: "error",
});
}
} catch (error) {
sdk.window.showToast(
`Error sending to replay: ${error instanceof Error ? error.message : "Unknown error"}`,
{ variant: "error" },
);
if (replayResult.kind === "Error") {
sdk.window.showToast(`Failed to create replay: ${replayResult.error}`, {
variant: "error",
});
return;
}

sdk.window.showToast(
`Created replay session: ${replayResult.value.sessionName}`,
{ variant: "success" },
);
};

const getAttackTypeLabel = (attackType: string) => {
Expand Down
5 changes: 4 additions & 1 deletion packages/frontend/src/components/common/CodeEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { lineNumbers } from "@codemirror/view";
import { EditorView } from "codemirror";
import { onMounted, onUnmounted, ref, watch } from "vue";

import { graphqlLanguage } from "./graphqlHighlight";

const props = defineProps<{
content: string;
language?: "json" | "javascript" | "graphql";
Expand All @@ -26,8 +28,9 @@ const getLanguageExtension = () => {
switch (props.language) {
case "json":
return json();
case "javascript":
case "graphql":
return graphqlLanguage;
case "javascript":
return javascript();
default:
return javascript();
Expand Down
40 changes: 40 additions & 0 deletions packages/frontend/src/components/common/graphqlHighlight.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { StreamLanguage } from "@codemirror/language";

const keywords = new Set([
"query",
"mutation",
"subscription",
"fragment",
"on",
"true",
"false",
"null",
]);

export const graphqlLanguage = StreamLanguage.define({
token(stream) {
if (stream.eatSpace()) return null;

if (stream.match(/^#.*/) !== null) return "comment";
if (stream.match(/^"(?:[^"\\]|\\.)*"/) !== null) return "string";
if (stream.match(/^\$[_A-Za-z][_A-Za-z0-9]*/) !== null)
return "variableName";
if (stream.match(/^@[_A-Za-z][_A-Za-z0-9]*/) !== null) return "meta";
if (stream.match(/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/) !== null) {
return "number";
}

const word = stream.match(/^[_A-Za-z][_A-Za-z0-9]*/);
if (word !== null && typeof word !== "boolean") {
const name = word[0] ?? "";
if (keywords.has(name)) return "keyword";
if (/^[A-Z]/.test(name)) return "typeName";
return "propertyName";
}

if (stream.match(/^[{}()[\]!:=,|&.]/) !== null) return "punctuation";

stream.next();
return null;
},
});
Loading
Loading