chore: resolve community scorecard warnings (security + deps + CSS)

This commit is contained in:
James Clifford Spratt 2026-06-29 13:12:03 +01:00
parent 8cfe718677
commit 1a8b3b3fef
8 changed files with 4436 additions and 1108 deletions

View file

@ -1,6 +1,6 @@
import esbuild from 'esbuild';
import process from 'process';
import builtins from 'builtin-modules';
import { builtinModules } from 'node:module';
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
@ -29,7 +29,7 @@ const context = await esbuild.context({
'@lezer/common',
'@lezer/highlight',
'@lezer/lr',
...builtins,
...builtinModules,
],
format: 'cjs',
platform: 'node',

View file

@ -2,7 +2,7 @@
"id": "macros",
"name": "Macros",
"version": "2.6.1",
"minAppVersion": "1.4.10",
"minAppVersion": "1.5.7",
"description": "Track daily nutrition, calories, protein, fat, and carbs with interactive tables and charts. Create meal templates, search foods via FatSecret API, and visualize macro data with customizable pie charts and multi-day analytics.",
"author": "James Spratt",
"authorUrl": "https://github.com/JamesCliffordSpratt",

5481
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -22,24 +22,22 @@
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@types/crypto-js": "^4.2.2",
"@types/jest": "^29.5.14",
"@types/node": "^16.11.6",
"@typescript-eslint/eslint-plugin": "^8.62.0",
"@typescript-eslint/parser": "^8.62.0",
"builtin-modules": "3.3.0",
"esbuild": "^0.28.1",
"eslint": "^9.39.4",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-obsidianmd": "^0.3.0",
"eslint-plugin-prettier": "^5.2.6",
"eslint-plugin-unused-imports": "^4.1.4",
"jest": "^29.7.0",
"jest": "^30.4.2",
"jest-environment-jsdom": "^29.7.0",
"obsidian": "latest",
"prettier": "^3.5.3",
"standard-version": "^9.5.0",
"ts-jest": "^29.3.2",
"ts-jest": "^29.4.11",
"tslib": "2.4.0",
"typescript": "^5.9.3"
},
@ -47,7 +45,6 @@
"@zxing/browser": "^0.1.5",
"@zxing/library": "^0.21.3",
"chart.js": "^4.4.9",
"crypto-js": "^4.2.0",
"fuse.js": "^7.1.0"
}
}

View file

@ -1,5 +1,4 @@
import { App, requestUrl } from 'obsidian';
import * as CryptoJS from 'crypto-js';
import { extractServingSize } from '../utils';
import { toCanonicalMicronutrient } from '../utils/nutrition/micronutrients';
/*
@ -74,6 +73,28 @@ const FATSECRET_FIELD_TO_KEY: Record<string, { key: string; unit: string }> = {
cholesterol: { key: 'cholesterol', unit: 'mg' },
};
/**
* Compute an HMAC-SHA1 signature of `message` keyed by `key` and return it
* Base64-encoded, using the built-in Web Crypto API (replaces crypto-js).
*/
async function hmacSha1Base64(message: string, key: string): Promise<string> {
const enc = new TextEncoder();
const cryptoKey = await crypto.subtle.importKey(
'raw',
enc.encode(key),
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
);
const sigBuffer = await crypto.subtle.sign('HMAC', cryptoKey, enc.encode(message));
const bytes = new Uint8Array(sigBuffer);
let binary = '';
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
export async function fetchFoodData(
app: App,
foodName: string,
@ -122,10 +143,8 @@ export async function fetchFoodData(
// Create signing key
const signingKey = `${encodeURIComponent(apiSecret)}&`;
// Generate signature using CryptoJS
const signature = CryptoJS.HmacSHA1(signatureBaseString, signingKey).toString(
CryptoJS.enc.Base64
);
// Generate signature using the Web Crypto API
const signature = await hmacSha1Base64(signatureBaseString, signingKey);
// Add signature to parameters
const requestParams = {
@ -174,11 +193,11 @@ function generateNonce(): string {
* Build an OAuth 1.0 (HMAC-SHA1) signed FatSecret REST URL for the given
* method-specific parameters.
*/
function buildSignedFatSecretUrl(
async function buildSignedFatSecretUrl(
methodParams: Record<string, string>,
apiKey: string,
apiSecret: string
): string {
): Promise<string> {
const baseUrl = 'https://platform.fatsecret.com/rest/server.api';
const params: Record<string, string> = {
format: 'json',
@ -202,9 +221,7 @@ function buildSignedFatSecretUrl(
].join('&');
const signingKey = `${encodeURIComponent(apiSecret)}&`;
const signature = CryptoJS.HmacSHA1(signatureBaseString, signingKey).toString(
CryptoJS.enc.Base64
);
const signature = await hmacSha1Base64(signatureBaseString, signingKey);
const urlParams = new URLSearchParams();
Object.entries({ ...params, oauth_signature: signature }).forEach(([key, value]) => {
@ -252,7 +269,7 @@ export async function fetchFatSecretMicronutrients(
apiSecret: string
): Promise<FatSecretMicronutrients | null> {
try {
const url = buildSignedFatSecretUrl(
const url = await buildSignedFatSecretUrl(
{ method: 'food.get.v4', food_id: foodId },
apiKey,
apiSecret

View file

@ -489,7 +489,7 @@ export class NutritionalSettingTab extends PluginSettingTab {
// kcal input
const kcalContainer = controlContainer.createDiv({ cls: 'energy-input-group' });
kcalContainer.createEl('label', {
// eslint-disable-next-line obsidianmd/ui/sentence-case
// eslint-disable-next-line obsidianmd/ui/sentence-case -- intentional casing (unit symbol, URL, or acronym; not sentence prose)
text: 'kcal',
cls: 'energy-input-label',
});
@ -507,7 +507,7 @@ export class NutritionalSettingTab extends PluginSettingTab {
// kJ input
const kjContainer = controlContainer.createDiv({ cls: 'energy-input-group' });
kjContainer.createEl('label', {
// eslint-disable-next-line obsidianmd/ui/sentence-case
// eslint-disable-next-line obsidianmd/ui/sentence-case -- intentional casing (unit symbol, URL, or acronym; not sentence prose)
text: 'kJ',
cls: 'energy-input-label',
});
@ -882,7 +882,7 @@ export class NutritionalSettingTab extends PluginSettingTab {
});
fatSecretNotice.createEl('a', {
// eslint-disable-next-line obsidianmd/ui/sentence-case
// eslint-disable-next-line obsidianmd/ui/sentence-case -- intentional casing (unit symbol, URL, or acronym; not sentence prose)
text: 'https://platform.fatsecret.com/platform-api',
attr: { href: 'https://platform.fatsecret.com/platform-api', target: '_blank' },
});

View file

@ -935,7 +935,7 @@ class ManualBarcodeEntryModal extends Modal {
contentEl.createEl('h2', { text: 'Enter barcode manually' });
contentEl.createEl('p', {
// eslint-disable-next-line obsidianmd/ui/sentence-case
// eslint-disable-next-line obsidianmd/ui/sentence-case -- intentional casing (unit symbol, URL, or acronym; not sentence prose)
text: 'Enter the numbers from the barcode (EAN/UPC codes are typically 8-13 digits):',
cls: 'modal-description',
});

View file

@ -466,8 +466,6 @@ tr[data-macro-line]:hover {
overflow: visible;
text-overflow: unset;
white-space: normal;
font-weight: inherit;
color: inherit;
background: none;
font-weight: 600;
color: var(--text-normal);
@ -475,7 +473,6 @@ tr[data-macro-line]:hover {
.header-calorie-summary {
flex-shrink: 0;
margin-left: 8px;
opacity: 0.8;
background: none;
color: var(--text-muted);