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
12 changes: 11 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ module.exports = {
env: {
es2021: true,
},
extends: ["plugin:vue/recommended", "@vue/eslint-config-airbnb", "prettier"],
extends: [
"plugin:vue/vue3-recommended",
"@vue/eslint-config-airbnb",
"prettier",
],
rules: {
"no-console": process.env.NODE_ENV === "production" ? "error" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
Expand Down Expand Up @@ -61,5 +65,11 @@ module.exports = {
mocha: true,
},
},
{
files: ["src/plugins/vuetify.js"],
rules: {
"import/no-unresolved": "off",
},
},
],
};
2 changes: 1 addition & 1 deletion .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
cache: "yarn"
- name: Get app version
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-private-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
git config user.email noreply@github.com
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
- name: Change version number
run: |
if [ -n "${{ github.event.inputs.overrideVersion }}" ]; then
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-private-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
git config user.email noreply@github.com
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
- name: Set application version as variable
run: |
echo "APP_VERSION=$(npm pkg get version | sed 's/"//g')" >> $GITHUB_ENV
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-public-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
git config user.email noreply@github.com
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
- name: Get app version
run: |
echo "APP_VERSION=$(npm pkg get version | sed 's/"//g')" >> $GITHUB_ENV
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-public-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
echo "LATEST_TAG=$latest_tag" >> $GITHUB_ENV
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
cache: "yarn"
- name: Set application version as variable
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-sponsor-kali-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
git config user.email noreply@github.com
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
- name: Get app version
run: |
echo "APP_VERSION=$(npm pkg get version | sed 's/"//g')" >> $GITHUB_ENV
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-sponsor-kali-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
git config user.email noreply@github.com
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 20
cache: "yarn"
- name: Set application version as variable
run: |
Expand Down
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.4.0] - 2026-03-08

### Changed

- Migrated from Vue 2 to Vue 3
- Migrated from Vuetify 2 to Vuetify 3
- Replaced vue-beautiful-chat with native Vuetify 3 chat drawer
- Updated CI workflows to Node 20

### Added

- Added Jobs tab to agent page for viewing and managing background jobs
- Added ability to kill background jobs from the Jobs tab

### Fixed

- Fixed module execution snackbar displaying "[object Object]" instead of agent name
- Fixed bulk delete on malleable profiles page using wrong identifier

## [3.3.0] - 2026-01-18

### Added
Expand Down Expand Up @@ -445,7 +459,9 @@ Including but not limited to:

- Initial Release

[Unreleased]: https://github.com/BC-SECURITY/Starkiller-Sponsors/compare/v3.3.0...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Starkiller-Sponsors/compare/v3.4.0...HEAD

[3.4.0]: https://github.com/BC-SECURITY/Starkiller-Sponsors/compare/v3.3.0...v3.4.0

[3.3.0]: https://github.com/BC-SECURITY/Starkiller-Sponsors/compare/v3.2.0...v3.3.0

Expand Down
26 changes: 12 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "starkiller",
"version": "3.3.0",
"version": "3.4.0",
"private": true,
"scripts": {
"dev": "vite",
Expand All @@ -14,37 +14,35 @@
"dependencies": {
"@fontsource/roboto": "^4.5.1",
"@fortawesome/fontawesome-free": "^6",
"@mdi/font": "5.9.55",
"@mdi/font": "^7.0",
"ansi_up": "^5.2.1",
"axios": "^0.24.0",
"lodash.debounce": "^4.0.8",
"moment": "^2.29.1",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0",
"portal-vue": "^2.1.7",
"qs": "^6.10.3",
"semver": "^7.3.5",
"socket.io-client": "^4.1.2",
"splitpanes": "^2.3.8",
"splitpanes": "^3.1.0",
"table": "^6.8.1",
"uuid": "^8.3.2",
"vue": "2.7",
"vue-beautiful-chat": "^2.5.0",
"vue-markdown-render": "1.1.2",
"vue-router": "^3.5.1",
"vuedraggable": "^2.24.3",
"vuetify": "^2.6.0"
"vue": "^3.5",
"vue-markdown-render": "^2.3.0",
"vue-router": "^4.3",
"vuedraggable": "^4.1",
"vuetify": "^3.12"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@vitejs/plugin-vue2": "^2.2.0",
"@vitejs/plugin-vue": "^5.0",
"@vue/eslint-config-airbnb": "^7.0.0",
"eslint": "^8.31.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-vue": "^9.8.0",
"prettier": "^3.0.2",
"sass": "~1.32",
"unplugin-vue-components": "^0.22.12",
"vite": "^4"
"sass": "^1.70",
"vite": "^5.0",
"vite-plugin-vuetify": "^2.0"
}
}
82 changes: 64 additions & 18 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
<confirm ref="confirm" />
<socket-notifications
v-if="isLoggedIn && versionSatisfies('>=4.0') && !hideSideBar"
ref="socketNotifications"
/>
<starkiller-snackbar ref="snack" />
<v-app-bar v-if="isLoggedIn" elevate-on-scroll app>
<v-app-bar v-if="isLoggedIn" scroll-behavior="elevate">
<template
v-if="
$route.name === 'agentEdit' ||
Expand All @@ -16,19 +17,33 @@
"
#extension
>
<portal-target name="app-bar-extension" slim />
<div
id="app-bar-extension"
style="display: flex; flex: 1 1 auto; align-items: center"
></div>
</template>
<portal-target name="app-bar" multiple slim />
<div
id="app-bar"
style="display: flex; flex: 1 1 auto; align-items: center"
></div>
<div v-if="isLoggedIn && chatWidget" class="pt-2">
<v-btn icon variant="text" size="small" @click="openChat">
<v-badge
:content="chatUnreadCount"
:model-value="chatUnreadCount > 0"
color="#F37C22"
>
<v-icon>mdi-chat</v-icon>
</v-badge>
</v-btn>
</div>
<notification-bell
v-show="$route.name !== 'notifications'"
ref="bell"
/>
</v-app-bar>
<!-- Sizes your content based upon application components -->
<v-main>
<!-- Provides the application the proper gutter -->
<v-container fluid>
<!-- If using vue-router -->
<router-view />
</v-container>
</v-main>
Expand Down Expand Up @@ -66,7 +81,6 @@
</div>
</template>
<script>
import Vue from "vue";
import semver from "semver";
import { mapState } from "pinia";

Expand All @@ -86,11 +100,49 @@ export default {
SocketNotifications,
StarkillerSnackbar,
},
provide() {
return {
snack: this.snackProxy,
bell: this.bellProxy,
confirm: (...args) => {
if (!this.$refs.confirm) {
console.warn("[Starkiller] confirm ref unavailable:", ...args);
return false;
}
return this.$refs.confirm.open(...args);
},
};
},
data() {
const createRefProxy = (refName, methods) =>
Object.fromEntries(
methods.map((method) => [
method,
(...args) => {
if (!this.$refs[refName]) {
console.error(
`[Starkiller] ${refName} ref unavailable, ${method}:`,
...args,
);
return;
}
this.$refs[refName][method](...args);
},
]),
);

return {
snackProxy: createRefProxy("snack", ["error", "warn", "success", "info"]),
bellProxy: createRefProxy("bell", ["push"]),
};
},
computed: {
...mapState(useApplicationStore, [
"isLoggedIn",
"empireVersion",
"connectionError",
"chatWidget",
"chatUnreadCount",
]),
isLoginPage() {
return this.$route.name === "home";
Expand Down Expand Up @@ -122,7 +174,7 @@ export default {
if (val.length > 0) {
if (semver.satisfies(val.split(" ")[0].split("-")[0], "<5.2")) {
await this.$nextTick();
this.$snack.warn(
this.snackProxy.warn(
"This version of Starkiller is recommended to be used with Empire 5.2 or greater." +
" Some features may not work properly.",
);
Expand All @@ -133,20 +185,14 @@ export default {
},
connectionError(val) {
if (val > 0) {
this.$snack.error("Could not reach Empire server");
this.snackProxy.error("Could not reach Empire server");
}
},
},
mounted() {
this.$root.$confirm = this.$refs.confirm.open;

// register global snackbar
Vue.prototype.$snack = this.$refs.snack;

// register global notification bell
Vue.prototype.$bell = this.$refs.bell;
},
methods: {
openChat() {
this.$refs.socketNotifications?.$refs.chat?.open();
},
versionSatisfies(version) {
return semver.satisfies(
this.empireVersion.split(" ")[0].split("-")[0],
Expand Down
9 changes: 5 additions & 4 deletions src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
margin-bottom: 15px;
}

.sc-launcher,
.sc-open-icon,
.sc-closed-icon {
bottom: 0 !important;
// Overrides vuetify.css
// Because Teleport wraps tabs in a div, which changes the background color.
.v-toolbar__content > div > .v-tabs,
.v-toolbar__extension > div > .v-tabs {
background-color: inherit;
}
5 changes: 2 additions & 3 deletions src/components/AuthorChips.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<template>
<div>
<template v-for="(author, index) in authors">
<template v-for="(author, index) in authors" :key="index">
<a
v-if="author.link"
:key="index"
:href="author.link"
target="_blank"
rel="noopener noreferrer"
Expand All @@ -14,7 +13,7 @@
</v-chip>
</a>

<v-chip v-else :key="index" medium class="mr-1 mb-1">
<v-chip v-else medium class="mr-1 mb-1">
{{ formatDisplayName(author) }}
</v-chip>
</template>
Expand Down
Loading
Loading