From 802fb625d75a26a203b9c55709b12dad3d879193 Mon Sep 17 00:00:00 2001 From: Alicia Sykes <=> Date: Sun, 26 Dec 2021 22:56:11 +0000 Subject: [PATCH 1/5] :sparkles: Adds widget for monitoring CVE vulnerabilities --- docs/widgets.md | 39 +++ src/components/Widgets/CveVulnerabilities.vue | 236 ++++++++++++++++ src/components/Widgets/WidgetBase.vue | 8 + src/styles/color-palette.scss | 255 +++++++++--------- src/utils/MiscHelpers.js | 5 + src/utils/defaults.js | 1 + 6 files changed, 417 insertions(+), 127 deletions(-) create mode 100644 src/components/Widgets/CveVulnerabilities.vue diff --git a/docs/widgets.md b/docs/widgets.md index 4dc3ccef..14d0db67 100644 --- a/docs/widgets.md +++ b/docs/widgets.md @@ -12,6 +12,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a - [RSS Feed](#rss-feed) - [XKCD Comics](#xkcd-comics) - [Code Stats](#code-stats) + - [Vulnerability Feed](#vulnerability-feed) - [Public Holidays](#public-holidays) - [TFL Status](#tfl-status) - [Exchange Rates](#exchange-rates) @@ -277,6 +278,44 @@ Display your coding summary. [Code::Stats](https://codestats.net/) is a free and --- +### Vulnerability Feed + +Display a feed of recent vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional. + +

+ +##### Options + +**Field** | **Type** | **Required** | **Description** +--- | --- | --- | --- +**`sortBy`** | `string` | _Optional_ | The sorting method. Can be either `publish-date`, `last-update` or `cve-code`. Defaults to `publish-date` +**`limit`** | `number` | _Optional_ | The number of results to fetch. Can be between `5` and `30`, defaults to `10` +**`minScore`** | `number` | _Optional_ | If set, will only display results with a CVE score higher than the number specified. Can be a number between `0` and `9.9`. By default, vulnerabilities of all CVE scores are shown +**`hasExploit`** | `boolean` | _Optional_ | If set to `true`, will only show results with active exploits. Defaults to `false` +**`vendorId`** | `number` | _Optional_ | Only show results from a specific vendor, specified by ID. See [Vendor Search](https://www.cvedetails.com/vendor-search.php) for list of vendors. E.g. `23` (Debian), `26` (Microsoft), `23682` (CloudFlare) +**`productId`** | `number` | _Optional_ | Only show results from a specific app or product, specified by ID. See [Product Search](https://www.cvedetails.com/product-search.php) for list of products. E.g. `13534` (Docker), `15913` (NextCloud), `19294` (Portainer), `17908` (ProtonMail) + + +##### Example + +```yaml +- type: cve-vulnerabilities +``` + +or + +```yaml +- type: cve-vulnerabilities + options: + sortBy: publish-date + productId: 28125 + hasExploit: true + minScore: 5 + limit: 30 +``` + +--- + ### Public Holidays Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from [Enrico](http://kayaposoft.com/enrico/) diff --git a/src/components/Widgets/CveVulnerabilities.vue b/src/components/Widgets/CveVulnerabilities.vue new file mode 100644 index 00000000..80f48dd8 --- /dev/null +++ b/src/components/Widgets/CveVulnerabilities.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/src/components/Widgets/WidgetBase.vue b/src/components/Widgets/WidgetBase.vue index f36c72de..ffc4b065 100644 --- a/src/components/Widgets/WidgetBase.vue +++ b/src/components/Widgets/WidgetBase.vue @@ -46,6 +46,13 @@ @error="handleError" :ref="widgetRef" /> + import('@/components/Widgets/CodeStats.vue'), CryptoPriceChart: () => import('@/components/Widgets/CryptoPriceChart.vue'), CryptoWatchList: () => import('@/components/Widgets/CryptoWatchList.vue'), + CveVulnerabilities: () => import('@/components/Widgets/CveVulnerabilities.vue'), EmbedWidget: () => import('@/components/Widgets/EmbedWidget.vue'), ExchangeRates: () => import('@/components/Widgets/ExchangeRates.vue'), Flights: () => import('@/components/Widgets/Flights.vue'), diff --git a/src/styles/color-palette.scss b/src/styles/color-palette.scss index 8a38381a..4398cbf3 100644 --- a/src/styles/color-palette.scss +++ b/src/styles/color-palette.scss @@ -1,127 +1,128 @@ -@import '@/styles/media-queries.scss'; - -:root { - /* Basic*/ - --primary: #5cabca; // Main accent color - --background: #0b1021; // Page background - --background-darker: #05070e; // Used for navigation bar, footer and fills - - /* Action Colors */ - --info: #04e4f4; - --success: #20e253; - --warning: #f6f000; - --danger: #f80363; - --neutral: #272f4d; - --white: #fff; - --black: #000; - - /* Modified Colors */ - --item-group-background: #0b1021cc; - --medium-grey: #5e6474; - --item-background: #607d8b33; - --item-background-hover: #607d8b4d; - - /* Semi-Transparent Black*/ - --transparent-70: #000000b3; - --transparent-50: #00000080; - --transparent-30: #0000004d; - - /* Semi-Transparent White*/ - --transparent-white-70: #ffffffb3; - --transparent-white-50: #ffffff80; - --transparent-white-30: #ffffff4d; - - /* Color variables for specific components - * all variables are optional, since they inherit initial values from above* - * Using specific variables makes overriding for custom themes really easy */ - --heading-text-color: var(--primary); - // Nav-bar links - --nav-link-text-color: var(--primary); - --nav-link-background-color: #607d8b33; - --nav-link-text-color-hover: var(--primary); - --nav-link-background-color-hover: #607d8b33; - --nav-link-border-color: transparent; - --nav-link-border-color-hover: var(--primary); - --nav-link-shadow: 1px 1px 2px #232323; - --nav-link-shadow-hover: 1px 1px 2px #232323; - // Link items and sections - --item-text-color: var(--primary); - --item-text-color-hover: var(--item-text-color); - --item-group-outer-background: var(--primary); - --item-group-heading-text-color: var(--item-group-background); - --item-group-heading-text-color-hover: var(--background); - // Homepage settings - --settings-text-color: var(--primary); - --settings-background: var(--background); - // Config menu - --config-settings-color: var(--primary); - --config-settings-background: var(--background-darker); - --config-code-color: var(--background); - --config-code-background: var(--white); - --code-editor-color: var(--black); - --code-editor-background: var(--white); - // Widgets - --widget-text-color: var(--primary); - --widget-background-color: var(--background-darker); - --widget-accent-color: var(--background); - // Interactive editor - --interactive-editor-color: var(--primary); - --interactive-editor-background: var(--background); - --interactive-editor-background-darker: var(--background-darker); - // Cloud backup/ restore menu - --cloud-backup-color: var(--config-settings-color); - --cloud-backup-background: var(--config-settings-background); - // Search bar (on homepage) - --search-container-background: var(--background-darker); - --search-field-background: var(--background); - --search-label-color: var(--settings-text-color); - // Page footer - --footer-text-color: var(--medium-grey); - --footer-text-color-link: var(--primary); - --footer-background: var(--background-darker); - // Right-click context menu - --context-menu-background: var(--background); - --context-menu-color: var(--primary); - --context-menu-secondary-color: var(--background-darker); - // Workspace view - --side-bar-background: var(--background-darker); - --side-bar-background-lighter: var(--background); - --side-bar-color: var(--primary); - --side-bar-item-background: var(--side-bar-background); - --side-bar-item-color: var(--side-bar-color); - // Minimal view - --minimal-view-background-color: var(--background); - --minimal-view-title-color: var(--primary); - --minimal-view-settings-color: var(--primary); - --minimal-view-section-heading-color: var(--primary); - --minimal-view-section-heading-background: var(--background-darker); - --minimal-view-search-background: var(--background-darker); - --minimal-view-search-color: var(--primary); - --minimal-view-group-color: var(--primary); - --minimal-view-group-background: var(--background-darker); - // Login page - --login-form-color: var(--primary); - --login-form-background: var(--background); - --login-form-background-secondary: var(--background-darker); - // About page - --about-page-color: var(--white); - --about-page-background: var(--background); - --about-page-accent: var(--primary); - // Webpage colors, highlight, scrollbar - --scroll-bar-color: var(--primary); - --scroll-bar-background: var(--background-darker); - --highlight-color: var(--background); - --highlight-background: var(--primary); - --progress-bar: var(--primary); - // Misc components - --loading-screen-color: var(--primary); - --loading-screen-background: var(--background); - --status-check-tooltip-background: var(--background-darker); - --status-check-tooltip-color: var(--primary); - --welcome-popup-background: var(--background-darker); - --welcome-popup-text-color: var(--primary); - --toast-background: var(--primary); - --toast-color: var(--background); - --description-tooltip-background: var(--background-darker); - --description-tooltip-color: var(--primary); -} +@import '@/styles/media-queries.scss'; + +:root { + /* Basic*/ + --primary: #5cabca; // Main accent color + --background: #0b1021; // Page background + --background-darker: #05070e; // Used for navigation bar, footer and fills + + /* Action Colors */ + --info: #04e4f4; + --success: #20e253; + --warning: #f6f000; + --error: #fca016; + --danger: #f80363; + --neutral: #272f4d; + --white: #fff; + --black: #000; + + /* Modified Colors */ + --item-group-background: #0b1021cc; + --medium-grey: #5e6474; + --item-background: #607d8b33; + --item-background-hover: #607d8b4d; + + /* Semi-Transparent Black*/ + --transparent-70: #000000b3; + --transparent-50: #00000080; + --transparent-30: #0000004d; + + /* Semi-Transparent White*/ + --transparent-white-70: #ffffffb3; + --transparent-white-50: #ffffff80; + --transparent-white-30: #ffffff4d; + + /* Color variables for specific components + * all variables are optional, since they inherit initial values from above* + * Using specific variables makes overriding for custom themes really easy */ + --heading-text-color: var(--primary); + // Nav-bar links + --nav-link-text-color: var(--primary); + --nav-link-background-color: #607d8b33; + --nav-link-text-color-hover: var(--primary); + --nav-link-background-color-hover: #607d8b33; + --nav-link-border-color: transparent; + --nav-link-border-color-hover: var(--primary); + --nav-link-shadow: 1px 1px 2px #232323; + --nav-link-shadow-hover: 1px 1px 2px #232323; + // Link items and sections + --item-text-color: var(--primary); + --item-text-color-hover: var(--item-text-color); + --item-group-outer-background: var(--primary); + --item-group-heading-text-color: var(--item-group-background); + --item-group-heading-text-color-hover: var(--background); + // Homepage settings + --settings-text-color: var(--primary); + --settings-background: var(--background); + // Config menu + --config-settings-color: var(--primary); + --config-settings-background: var(--background-darker); + --config-code-color: var(--background); + --config-code-background: var(--white); + --code-editor-color: var(--black); + --code-editor-background: var(--white); + // Widgets + --widget-text-color: var(--primary); + --widget-background-color: var(--background-darker); + --widget-accent-color: var(--background); + // Interactive editor + --interactive-editor-color: var(--primary); + --interactive-editor-background: var(--background); + --interactive-editor-background-darker: var(--background-darker); + // Cloud backup/ restore menu + --cloud-backup-color: var(--config-settings-color); + --cloud-backup-background: var(--config-settings-background); + // Search bar (on homepage) + --search-container-background: var(--background-darker); + --search-field-background: var(--background); + --search-label-color: var(--settings-text-color); + // Page footer + --footer-text-color: var(--medium-grey); + --footer-text-color-link: var(--primary); + --footer-background: var(--background-darker); + // Right-click context menu + --context-menu-background: var(--background); + --context-menu-color: var(--primary); + --context-menu-secondary-color: var(--background-darker); + // Workspace view + --side-bar-background: var(--background-darker); + --side-bar-background-lighter: var(--background); + --side-bar-color: var(--primary); + --side-bar-item-background: var(--side-bar-background); + --side-bar-item-color: var(--side-bar-color); + // Minimal view + --minimal-view-background-color: var(--background); + --minimal-view-title-color: var(--primary); + --minimal-view-settings-color: var(--primary); + --minimal-view-section-heading-color: var(--primary); + --minimal-view-section-heading-background: var(--background-darker); + --minimal-view-search-background: var(--background-darker); + --minimal-view-search-color: var(--primary); + --minimal-view-group-color: var(--primary); + --minimal-view-group-background: var(--background-darker); + // Login page + --login-form-color: var(--primary); + --login-form-background: var(--background); + --login-form-background-secondary: var(--background-darker); + // About page + --about-page-color: var(--white); + --about-page-background: var(--background); + --about-page-accent: var(--primary); + // Webpage colors, highlight, scrollbar + --scroll-bar-color: var(--primary); + --scroll-bar-background: var(--background-darker); + --highlight-color: var(--background); + --highlight-background: var(--primary); + --progress-bar: var(--primary); + // Misc components + --loading-screen-color: var(--primary); + --loading-screen-background: var(--background); + --status-check-tooltip-background: var(--background-darker); + --status-check-tooltip-color: var(--primary); + --welcome-popup-background: var(--background-darker); + --welcome-popup-text-color: var(--primary); + --toast-background: var(--primary); + --toast-color: var(--background); + --description-tooltip-background: var(--background-darker); + --description-tooltip-color: var(--primary); +} diff --git a/src/utils/MiscHelpers.js b/src/utils/MiscHelpers.js index 9d604cde..ad68301a 100644 --- a/src/utils/MiscHelpers.js +++ b/src/utils/MiscHelpers.js @@ -142,3 +142,8 @@ export const roundPrice = (price) => { else if (price <= 0.01) decimals = 5; return price.toFixed(decimals); }; + +/* Cuts string off at given length, and adds an ellipse */ +export const truncateStr = (str, len = 60, ellipse = '...') => { + return str.length > len + ellipse.length ? `${str.slice(0, len)}${ellipse}` : str; +}; diff --git a/src/utils/defaults.js b/src/utils/defaults.js index 829c147f..cd33c85c 100644 --- a/src/utils/defaults.js +++ b/src/utils/defaults.js @@ -211,6 +211,7 @@ module.exports = { codeStats: 'https://codestats.net/', cryptoPrices: 'https://api.coingecko.com/api/v3/coins/', cryptoWatchList: 'https://api.coingecko.com/api/v3/coins/markets/', + cveVulnerabilities: 'http://www.cvedetails.com/json-feed.php', exchangeRates: 'https://v6.exchangerate-api.com/v6/', flights: 'https://aerodatabox.p.rapidapi.com/flights/airports/icao/', githubTrending: 'https://gh-trending-repos.herokuapp.com/', From 970b417f442a296e1899b8b2b4648dd28f83e00d Mon Sep 17 00:00:00 2001 From: Alicia Sykes <=> Date: Sun, 26 Dec 2021 23:01:23 +0000 Subject: [PATCH 2/5] :bug: Fix logic in GH profile widget --- src/components/Widgets/GitHubProfile.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Widgets/GitHubProfile.vue b/src/components/Widgets/GitHubProfile.vue index d45f5418..4f7de097 100644 --- a/src/components/Widgets/GitHubProfile.vue +++ b/src/components/Widgets/GitHubProfile.vue @@ -23,7 +23,7 @@ export default { }, username() { const usersChoice = this.options.username; - if ((this.hideLanguagesCard || this.hideLanguagesCard) && !usersChoice) { + if ((!this.hideProfileCard || !this.hideLanguagesCard) && !usersChoice) { this.error('You must specify a GitHub username'); } return usersChoice; From 1324b43c0e682e79d139a10681a3c245eea79dbc Mon Sep 17 00:00:00 2001 From: Alicia Sykes <=> Date: Sun, 26 Dec 2021 23:14:25 +0000 Subject: [PATCH 3/5] :adhesive_bandage: Fixes all minor issues raised by DeepScan --- src/components/Widgets/CryptoPriceChart.vue | 2 +- src/components/Widgets/CryptoWatchList.vue | 2 +- src/components/Widgets/Flights.vue | 2 +- src/components/Widgets/PublicHolidays.vue | 2 +- src/components/Widgets/RssFeed.vue | 2 +- src/components/Widgets/StockPriceChart.vue | 2 +- src/components/Widgets/SystemInfo.vue | 2 +- src/components/Widgets/XkcdComic.vue | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Widgets/CryptoPriceChart.vue b/src/components/Widgets/CryptoPriceChart.vue index ab719740..5d220105 100644 --- a/src/components/Widgets/CryptoPriceChart.vue +++ b/src/components/Widgets/CryptoPriceChart.vue @@ -85,7 +85,7 @@ export default { axios.get(this.endpoint) .then((response) => { try { - this.lineStatuses = this.processData(response.data); + this.processData(response.data); } catch (chartingError) { this.error('Unable to plot results on chart', chartingError); } diff --git a/src/components/Widgets/CryptoWatchList.vue b/src/components/Widgets/CryptoWatchList.vue index 2bf3c635..115f42bf 100644 --- a/src/components/Widgets/CryptoWatchList.vue +++ b/src/components/Widgets/CryptoWatchList.vue @@ -47,7 +47,7 @@ export default { }, limit() { const userChoice = this.options.limit; - if (userChoice && !Number.isNaN(userChoice) && userChoice > 0) return userChoice; + if (userChoice && userChoice > 0) return userChoice; return 100; }, /* How results should be sorted */ diff --git a/src/components/Widgets/Flights.vue b/src/components/Widgets/Flights.vue index c9b0039b..1805f67d 100644 --- a/src/components/Widgets/Flights.vue +++ b/src/components/Widgets/Flights.vue @@ -83,7 +83,7 @@ export default { }, limit() { const usersChoice = this.options.limit; - if (usersChoice && !Number.isNaN(usersChoice)) return usersChoice; + if (usersChoice) return usersChoice; return 8; }, /* The starting date, right now, in ISO String format */ diff --git a/src/components/Widgets/PublicHolidays.vue b/src/components/Widgets/PublicHolidays.vue index c22cc522..2c4690e9 100644 --- a/src/components/Widgets/PublicHolidays.vue +++ b/src/components/Widgets/PublicHolidays.vue @@ -40,7 +40,7 @@ export default { }, monthsToShow() { const usersChoice = this.options.monthsToShow; - if (usersChoice && !Number.isNaN(usersChoice) && usersChoice > 0 && usersChoice <= 24) { + if (usersChoice && usersChoice > 0 && usersChoice <= 24) { return usersChoice; } return 12; diff --git a/src/components/Widgets/RssFeed.vue b/src/components/Widgets/RssFeed.vue index e737ab84..06fc3e75 100644 --- a/src/components/Widgets/RssFeed.vue +++ b/src/components/Widgets/RssFeed.vue @@ -53,7 +53,7 @@ export default { }, limit() { const usersChoice = this.options.limit; - if (usersChoice && !Number.isNaN(usersChoice)) return usersChoice; + if (usersChoice) return usersChoice; return 10; }, orderBy() { diff --git a/src/components/Widgets/StockPriceChart.vue b/src/components/Widgets/StockPriceChart.vue index 655d5d52..a0438ce4 100644 --- a/src/components/Widgets/StockPriceChart.vue +++ b/src/components/Widgets/StockPriceChart.vue @@ -142,7 +142,7 @@ export default { }, /* Format the price, rounding to given number of decimal places */ formatPrice(priceStr) { - const price = parseInt(priceStr, 10); + const price = parseFloat(priceStr, 10); let numDecimals = 0; if (price < 10) numDecimals = 1; if (price < 1) numDecimals = 2; diff --git a/src/components/Widgets/SystemInfo.vue b/src/components/Widgets/SystemInfo.vue index 035abde8..96749512 100644 --- a/src/components/Widgets/SystemInfo.vue +++ b/src/components/Widgets/SystemInfo.vue @@ -40,7 +40,7 @@ export default { return username ? `${username}@` : ''; }, makeUptime(seconds) { - if (!seconds || seconds === 0) return ''; + if (!seconds) return ''; if (seconds < 60) return `${seconds} seconds`; if (seconds < 3600) return `${(seconds / 60).toFixed(1)} minutes`; if (seconds < 86400) return `${(seconds / 3600).toFixed(2)} hours`; diff --git a/src/components/Widgets/XkcdComic.vue b/src/components/Widgets/XkcdComic.vue index ba565f76..5ddd8468 100644 --- a/src/components/Widgets/XkcdComic.vue +++ b/src/components/Widgets/XkcdComic.vue @@ -31,7 +31,7 @@ export default { return 'latest'; } else if (usersChoice === 'random') { return Math.abs(Math.floor(Math.random() * (1 - 2553))); - } else if (!Number.isNaN(usersChoice)) { + } else if (usersChoice) { return usersChoice; } return 'latest'; From 9c6c35ea89108b652415f990cb768767afcbe7b0 Mon Sep 17 00:00:00 2001 From: Alicia Sykes <=> Date: Sun, 26 Dec 2021 23:38:44 +0000 Subject: [PATCH 4/5] :wheelchair: Fixes accesibility issues in some Widgets --- src/components/Widgets/Apod.vue | 2 +- src/components/Widgets/CryptoWatchList.vue | 2 +- src/components/Widgets/GitHubProfile.vue | 6 +++--- src/components/Widgets/GitHubTrending.vue | 2 +- src/components/Widgets/IframeWidget.vue | 1 + src/components/Widgets/NewsHeadlines.vue | 2 +- src/components/Widgets/PublicIp.vue | 2 +- src/components/Widgets/RssFeed.vue | 4 ++-- src/components/Widgets/StatPing.vue | 7 +++++-- 9 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/Widgets/Apod.vue b/src/components/Widgets/Apod.vue index 6bd9e0c6..5633cc70 100644 --- a/src/components/Widgets/Apod.vue +++ b/src/components/Widgets/Apod.vue @@ -4,7 +4,7 @@ {{ title }} - +

{{ truncatedDescription }}

diff --git a/src/components/Widgets/CryptoWatchList.vue b/src/components/Widgets/CryptoWatchList.vue index 115f42bf..0f11f232 100644 --- a/src/components/Widgets/CryptoWatchList.vue +++ b/src/components/Widgets/CryptoWatchList.vue @@ -7,7 +7,7 @@ class="asset-wrapper" v-tooltip="tooltip(asset.info)" > - +

{{ asset.name }}

{{ asset.price | formatPrice }}

diff --git a/src/components/Widgets/GitHubProfile.vue b/src/components/Widgets/GitHubProfile.vue index 4f7de097..8f24aa34 100644 --- a/src/components/Widgets/GitHubProfile.vue +++ b/src/components/Widgets/GitHubProfile.vue @@ -1,9 +1,9 @@ diff --git a/src/components/Widgets/GitHubTrending.vue b/src/components/Widgets/GitHubTrending.vue index 3045fe0a..cb65702a 100644 --- a/src/components/Widgets/GitHubTrending.vue +++ b/src/components/Widgets/GitHubTrending.vue @@ -1,7 +1,7 @@ diff --git a/src/components/Widgets/PublicIp.vue b/src/components/Widgets/PublicIp.vue index 93c3450f..bcb7513d 100644 --- a/src/components/Widgets/PublicIp.vue +++ b/src/components/Widgets/PublicIp.vue @@ -2,7 +2,7 @@