Skip to content

Commit

Permalink
feat: highlight suspicious packages (#288)
Browse files Browse the repository at this point in the history
  • Loading branch information
fraxken authored Dec 1, 2023
1 parent 10ad62d commit c3c2edc
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 26 deletions.
104 changes: 90 additions & 14 deletions public/css/views/home.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@

.home--header--scorecard .description {
width: 190px;
background: linear-gradient(to bottom, #37474f 0%,#263238 100%);
background: linear-gradient(to bottom, #37474f 0%, #263238 100%);
display: flex;
align-items: center;
}

.home--header--scorecard .description > img {
.home--header--scorecard .description>img {
height: 73px;
}

.home--header--scorecard .description > p {
.home--header--scorecard .description>p {
margin-left: 10px;
}

Expand All @@ -48,20 +48,24 @@
text-shadow: 1px 1px 5px #0000007a;
box-shadow: 2px 2px 10px #1e1e1e69 inset;
}

.home--header--scorecard .score.green {
background-color: rgb(113 203 45);
}

.home--header--scorecard .score.red {
background-color: rgb(219 80 58);
}

.home--header--scorecard .score.orange {
background-color: rgb(252 196 39);
}

.home--header--scorecard .score.blue {
background-color: rgb(39 144 252);
}

.home--header--title {
.home--header--title {
display: flex;
flex-direction: column;
flex-grow: 1;
Expand Down Expand Up @@ -142,6 +146,7 @@
color: var(--secondary-darker);
flex-grow: 1;
flex-basis: 100%;
margin-top: 10px;
}

#home--view .home--body .pannel {
Expand Down Expand Up @@ -209,6 +214,22 @@
min-height: 20px;
}

#home--view .home--body .module>.content+.content {
margin-top: 10px;
}

#home--view .home--body .module>.content>p {
color: #7a7595;
display: flex;
align-items: center;
justify-content: center;
height: 40px;
font-family: "system-ui";
font-weight: 500;
letter-spacing: 1.1px;
padding: 10px;
}

/**
* WARNINGS BEGIN
*/
Expand All @@ -221,16 +242,13 @@

.home--warnings>p {
padding: 10px;
background: -moz-linear-gradient(left, rgba(140, 0, 0, 0.24) 0%, rgba(0, 0, 0, 0) 100%);
background: -webkit-linear-gradient(left, rgba(140, 0, 0, 0.24) 0%, rgba(0, 0, 0, 0) 100%);
background: linear-gradient(to right, rgba(140, 0, 0, 0.24) 0%, rgba(0, 0, 0, 0) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3d8c0000', endColorstr='#00000000', GradientType=1);

color: #4a0000;
border-left: 2px solid #da4e44;
background: linear-gradient(to right, rgb(231, 206, 195) 0%, rgba(255, 255, 255, 0) 100%);
color: #992323;
border-radius: 4px;
}

.home--warnings>p + p {
.home--warnings>p+p {
margin-top: 5px;
}

Expand Down Expand Up @@ -282,6 +300,63 @@
margin-top: 10px;
}

.home--packages--overview {
display: flex;
flex-direction: column;
margin-left: -10px;
margin-top: -10px;
}

.home--packages--overview>div {
background: linear-gradient(to right, rgb(231 216 195) 0%, rgba(255, 255, 255, 0) 100%);
display: flex;
align-items: center;
padding: 5px 10px;
position: relative;
box-sizing: border-box;
border-radius: 4px;
font-family: "mononoki";
margin-left: 10px;
margin-top: 10px;
border-left: 2px solid #da9744;
color: #992323;
font-size: 16px;
flex-wrap: wrap;
transition: 0.5s linear all;
}

.home--packages--overview>div:hover {
border-color: #da4e44;
cursor: pointer;
background: linear-gradient(to right, rgb(231, 206, 195) 0%, rgba(255, 255, 255, 0) 100%);
}

.home--packages--overview>div span {
color: #6d5703;
margin-left: 10px;
}

.home--packages--overview>div>div.chips {
margin-left: auto;
display: flex;
font-size: 15px;
font-family: 'Roboto';
font-weight: 500;
}

.home--packages--overview>div>div.chips>p {
padding: 5px;
background: linear-gradient(to bottom, rgba(252, 252, 252, 1) 0%, rgba(232, 232, 232, 1) 100%);
border-radius: 4px;
box-shadow: 2px 2px 6px 0px #71060633;
border: 1px solid #8f0e0e54;
color: #611717;
}

.home--packages--overview>div>div.chips>p+p {
margin-left: 10px;
}

/**
* OVERVIEW END
*/
Expand All @@ -299,7 +374,8 @@
.home--maintainers>.person {
height: 50px;
flex-basis: 300px;
display : flex;
background: linear-gradient(to bottom, rgba(252, 252, 252, 1) 0%, rgba(232, 232, 232, 1) 100%);
display: flex;
position: relative;
box-sizing: border-box;
border-radius: 4px;
Expand All @@ -317,15 +393,15 @@
}

.home--maintainers>.person.url:hover {
border-color: var(--primary);
border-color: var(--secondary-darker);
cursor: pointer;
}

.home--maintainers>.person>img {
width: 50px;
}

.home--maintainers>.person>i{
.home--maintainers>.person>i {
margin-right: 10px;
display: flex;
align-items: center;
Expand Down
94 changes: 92 additions & 2 deletions public/js/components/home.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
// Import Third-party Dependencies
import { NodeSecureDataSet, getJSON } from "@nodesecure/vis-network";
import { NodeSecureDataSet, getFlagsEmojisInlined, getJSON } from "@nodesecure/vis-network";
import { licenseIdConformance } from "@nodesecure/licenses-conformance";

// Import Internal Dependencies
import * as utils from "../utils.js";
import { Gauge } from "./gauge.js";
import { fetchScorecardData, getScoreColor, getScorecardLink } from "../scorecard.js";

// CONSTANTS
const kFlagsToWatch = new Set([
"hasBannedFile",
"isDeprecated",
"hasVulnerabilities",
"hasScript"
]);

const kEmojiDescription = {
"📦": "scripts",
"⚔️": "sensitive files",
"🚨": "vulnerabilities"
};

export class HomeView {
/**
* @param {!NodeSecureDataSet} secureDataSet
*/
constructor(secureDataSet) {
constructor(
secureDataSet,
nsn
) {
this.secureDataSet = secureDataSet;
this.nsn = nsn;

this.generateScorecard();
this.generateHeader();
this.generateOverview();
this.generatePackagesToWatch();
this.generateWarnings();
this.generateExtensions();
this.generateLicenses();
Expand Down Expand Up @@ -137,6 +156,77 @@ export class HomeView {
}
}

generatePackagesToWatch() {
const maxPackages = 4;
const fragment = document.createDocumentFragment();

const deps = [];
for (const dependency of Object.values(this.secureDataSet.data.dependencies)) {
for (const dependencyVer of Object.values(dependency.versions)) {
const { flags } = dependencyVer;

const hasFlag = flags.some((name) => kFlagsToWatch.has(name));
if (hasFlag) {
deps.push(dependencyVer);
}
}
}

const hideItems = deps.length > maxPackages;
for (let id = 0; id < deps.length; id++) {
const dependency = deps[id];

const element = this.renderPackage(dependency);
element.addEventListener("click", () => {
window.navigation.setNavByName("network--view");
setTimeout(() => this.nsn.focusNodeByName(dependency.name), 25);
});
if (hideItems && id >= maxPackages) {
element.classList.add("hidden");
}

fragment.appendChild(element);
}

if (fragment.children.length === 0) {
document.querySelector(".home--to--watch").style.display = "none";
}
else {
if (hideItems) {
fragment.appendChild(utils.createExpandableSpan(maxPackages));
}

document.querySelector(".home--packages--overview")
.appendChild(fragment);
}
}

renderPackage(dependencyVer) {
const { name, version, flags } = dependencyVer;
const inlinedEmojis = getFlagsEmojisInlined(
flags.filter((name) => kFlagsToWatch.has(name)),
new Set(window.settings.config.ignore.flags)
);

const childs = utils.extractEmojis(inlinedEmojis)
.map((emoji) => utils.createDOMElement("p", { text: `${emoji} ${kEmojiDescription[emoji]}` }));

return utils.createDOMElement("div", {
childs: [
utils.createDOMElement("p", {
childs: [
document.createTextNode(name),
utils.createDOMElement("span", { text: `v${version}` })
]
}),
utils.createDOMElement("div", {
className: "chips",
childs
})
]
});
}

generateWarnings() {
const warningsModuleElement = document.getElementById("warnings-module");
if (this.secureDataSet.warnings.length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion public/js/master.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ document.addEventListener("DOMContentLoaded", async () => {
});
await secureDataSet.init();

new HomeView(secureDataSet);
window.vulnerabilityStrategy = secureDataSet.data.vulnerabilityStrategy;

// Initialize vis Network
NodeSecureNetwork.networkElementId = "dependency-graph";
const nsn = new NodeSecureNetwork(secureDataSet);
new HomeView(secureDataSet, nsn);
const rootNodeParams = {
nodes: [0],
edges: nsn.network.getConnectedEdges(0)
Expand Down
9 changes: 9 additions & 0 deletions public/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ export function isGitLabHost(host) {
}
}

export function extractEmojis(strWithEmojis) {
const segmenter = new Intl.Segmenter("en", {
granularity: "grapheme"
});
const segitr = segmenter.segment(strWithEmojis.replaceAll(" ", ""));

return Array.from(segitr, ({ segment }) => segment);
}

/**
* @param {keyof HTMLElementTagNameMap} kind
* @param {object} [options]
Expand Down
22 changes: 13 additions & 9 deletions views/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,9 @@
<div class="content">
<div class="home--overview"></div>
</div>
</div>
<div class="module" id="warnings-module">
<div class="title warning">
<i class="icon-warning"></i>
<p>Warnings</p>
<span class="count">1</span>
</div>
<div class="content">
<div class="home--warnings"></div>
<div class="content" class="home--to--watch">
<p>Packages in the dependency tree requiring greater attention</p>
<div class="home--packages--overview"></div>
</div>
</div>
<div class="module">
Expand All @@ -113,6 +107,16 @@
</div>
</div>
<div class="pannel">
<div class="module" id="warnings-module">
<div class="title warning">
<i class="icon-warning"></i>
<p>Critical Warnings</p>
<span class="count">1</span>
</div>
<div class="content">
<div class="home--warnings"></div>
</div>
</div>
<div class="module">
<div class="title">
<i class="icon-doc"></i>
Expand Down

0 comments on commit c3c2edc

Please sign in to comment.