Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background: #f7f7f7;
color: #333;
line-height: 1.6;
}

header {
background: #4a90e2;
color: white;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
Comment on lines +1 to +21
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability, it's best to declare colors as CSS variables. This makes it easy to manage your color palette from one place. I've started the conversion here, which you should continue for other hardcoded colors in this file (e.g., on lines 43, 51, 92, 117).

:root {
  --primary-color: #4a90e2;
  --background-color: #f7f7f7;
  --text-color: #333;
  --text-on-primary: white;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background: var(--background-color);
  color: var(--text-color);
  line-height: 1.6;
}

header {
  background: var(--primary-color);
  color: var(--text-on-primary);
  padding: 15px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}


header h1 {
font-size: 24px;
}

.search-bar {
display: flex;
gap: 10px;
}

.search-bar input {
padding: 8px;
border-radius: 4px;
border: none;
width: 200px;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The search input has a fixed width of 200px. This is not responsive and can cause layout issues on smaller screens. Since its parent .search-bar is a flex container, you can make the input flexible by setting flex: 1;. This will allow it to grow and shrink as needed.

  flex: 1;

}

.search-bar button {
padding: 8px 12px;
border: none;
border-radius: 4px;
background: white;
color: #4a90e2;
cursor: pointer;
font-weight: bold;
transition: background 0.3s;
}

.search-bar button:hover {
background: #e2e2e2;
}

main {
padding: 20px;
}

.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 20px;
}

.product-card {
background: white;
border-radius: 8px;
padding: 15px;
text-align: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
cursor: pointer;
transition: transform 0.2s;
}

.product-card:hover {
transform: translateY(-5px);
}

.product-card img {
max-width: 100%;
height: 150px;
object-fit: contain;
margin-bottom: 10px;
}

.product-card h3 {
font-size: 18px;
margin-bottom: 8px;
}

.product-card p {
font-size: 16px;
color: #4a90e2;
font-weight: bold;
}

#product-details {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
margin-top: 20px;
}

#product-details img {
max-width: 300px;
display: block;
margin-bottom: 15px;
}

.hidden {
display: none;
}

footer {
margin-top: 40px;
padding: 15px;
background: #4a90e2;
color: white;
text-align: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"use strict";

const productList = document.getElementById("product-list");
const productDetails = document.getElementById("product-details");
const searchInput = document.getElementById("search-input");
const searchBtn = document.getElementById("search-btn");
const allBtn = document.getElementById("all-btn");

async function fetchProducts() {
try {
const res = await fetch("https://dummyjson.com/products?limit=30");
if (!res.ok) throw new Error("Unable to load products");
const data = await res.json();
return data.products;
} catch (err) {
productList.innerHTML = `<p class="error">${err.message}</p>`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using innerHTML to display error messages is a risky practice. While your current error messages are static strings, if an error message from an API response were ever displayed this way, it could lead to a Cross-Site Scripting (XSS) vulnerability. It's safer to use textContent to prevent the browser from interpreting the message as HTML. You can apply an error class to the productList element itself for styling. This feedback also applies to lines 27 and 37.

Suggested change
productList.innerHTML = `<p class="error">${err.message}</p>`;
productList.textContent = err.message;

}
}

async function searchProducts(query) {
try {
const res = await fetch(`https://dummyjson.com/products/search?q=${query}`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The search query is being inserted directly into the fetch URL. User input should always be properly encoded when used in a URL to prevent issues like malformed URLs or potential injection attacks if the endpoint is vulnerable. Use encodeURIComponent() to safely encode the query parameter.

Suggested change
const res = await fetch(`https://dummyjson.com/products/search?q=${query}`);
const res = await fetch(`https://dummyjson.com/products/search?q=${encodeURIComponent(query)}`);

if (!res.ok) throw new Error("Search failed");
const data = await res.json();
return data.products;
} catch (err) {
productList.innerHTML = `<p class="error">${err.message}</p>`;
}
}

async function getProduct(id) {
try {
const res = await fetch(`https://dummyjson.com/products/${id}`);
if (!res.ok) throw new Error("Unable to fetch product details");
return await res.json();
} catch (err) {
productDetails.innerHTML = `<p class="error">${err.message}</p>`;
}
}

function renderProducts(products) {
productDetails.classList.add("hidden");
productList.innerHTML = "";
products.forEach(p => {
const card = document.createElement("div");
card.className = "product-card";
card.innerHTML = `
<img src="${p.thumbnail}" alt="${p.title}">
<h3>${p.title}</h3>
<p>$${p.price}</p>
`;
card.addEventListener("click", () => showProduct(p.id));
productList.appendChild(card);
Comment on lines +45 to +53
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using innerHTML to inject HTML from API data is a major security risk and can lead to Cross-Site Scripting (XSS) attacks. If the API returns malicious data (e.g., a product title containing a <script> tag), it will be executed in the user's browser. You should create DOM elements programmatically and set their content using textContent to automatically sanitize the data.

    const card = document.createElement("div");
    card.className = "product-card";

    const img = document.createElement("img");
    img.src = p.thumbnail;
    img.alt = p.title;

    const title = document.createElement("h3");
    title.textContent = p.title;

    const price = document.createElement("p");
    price.textContent = `$${p.price}`;

    card.append(img, title, price);
    card.addEventListener("click", () => showProduct(p.id));
    productList.appendChild(card);

});
}

async function showProduct(id) {
const product = await getProduct(id);
if (product) {
productDetails.classList.remove("hidden");
productDetails.innerHTML = `
<h2>${product.title}</h2>
<img src="${product.thumbnail}" alt="${product.title}">
<p>${product.description}</p>
<p><strong>Price:</strong> $${product.price}</p>
<p><strong>Brand:</strong> ${product.brand}</p>
<p><strong>Category:</strong> ${product.category}</p>
`;
Comment on lines +61 to +68
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Similar to the renderProducts function, using innerHTML here with data from the API response creates a serious Cross-Site Scripting (XSS) vulnerability. Any malicious HTML in the product data could be executed. Please refactor this to create DOM elements safely and use textContent and append to build the structure.

    productDetails.innerHTML = '';

    const titleEl = document.createElement('h2');
    titleEl.textContent = product.title;

    const imgEl = document.createElement('img');
    imgEl.src = product.thumbnail;
    imgEl.alt = product.title;

    const descriptionEl = document.createElement('p');
    descriptionEl.textContent = product.description;

    const priceEl = document.createElement('p');
    priceEl.innerHTML = `<strong>Price:</strong> `;
    priceEl.append(`$${product.price}`);

    const brandEl = document.createElement('p');
    brandEl.innerHTML = `<strong>Brand:</strong> `;
    brandEl.append(product.brand);

    const categoryEl = document.createElement('p');
    categoryEl.innerHTML = `<strong>Category:</strong> `;
    categoryEl.append(product.category);

    productDetails.append(titleEl, imgEl, descriptionEl, priceEl, brandEl, categoryEl);

window.scrollTo({ top: productDetails.offsetTop - 20, behavior: "smooth" });
}
}

async function loadAllProducts() {
const products = await fetchProducts();
if (products) renderProducts(products);
}

async function handleSearch() {
const query = searchInput.value.trim();
if (!query) return;
const products = await searchProducts(query);
if (products) renderProducts(products);
}

searchBtn.addEventListener("click", handleSearch);
allBtn.addEventListener("click", loadAllProducts);

window.addEventListener("load", loadAllProducts);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ShopEase - Simple E-Commerce</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/shop.css">
</head>
<body>
<header>
<h1>ShopEase</h1>
<div class="search-bar">
<input type="text" id="search-input" placeholder="Search products...">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This input field is missing a <label>, which is an accessibility issue. Screen readers use labels to describe form controls to users. While a placeholder is present, it's not a replacement for a proper label. You can add an aria-label attribute to provide an accessible name for the input.

Suggested change
<input type="text" id="search-input" placeholder="Search products...">
<input type="text" id="search-input" placeholder="Search products..." aria-label="Search products">

<button id="search-btn">Search</button>
<button id="all-btn">All Products</button>
</div>
</header>

<main>
<section id="products-section">
<div id="product-list" class="grid"></div>
</section>
<section id="product-details" class="hidden"></section>
</main>

<footer>
<p>© 2025 ShopEase. All rights reserved.</p>
</footer>

<script src="./scripts/shop.js" defer></script>
</body>
</html>
15 changes: 15 additions & 0 deletions javascript/10-fetch-security-debugging/supriya/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>Javascript Assignments | Supriya Dasari</title>
</head>
<body>
<details>
<summary>Assignment 1</summary>
<iframe src="./assignment-1/shop.html" frameborder="0" width="100%"></iframe>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The frameborder attribute is obsolete in HTML5 and should not be used. Styling of frames should be handled with CSS. Additionally, for accessibility, it's important to provide a title attribute for <iframe> elements to describe their content to screen reader users. I've also added a default height to ensure the content is visible.

Suggested change
<iframe src="./assignment-1/shop.html" frameborder="0" width="100%"></iframe>
<iframe src="./assignment-1/shop.html" style="border: none; width: 100%; height: 600px;" title="E-commerce shop assignment"></iframe>

</details>
</body>
</html>