Skip to content

Commit

Permalink
(core) updates from grist-core
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfitz committed Dec 23, 2024
2 parents 1aff953 + e280ece commit 72a8412
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 7 deletions.
20 changes: 20 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Security Policy

## Supported Versions

| Version | Supported |
| ------- | ------------------ |
| >= 1.3.2 | :white_check_mark: |
| < 1.3.2 | upgrade required |

## Reporting a Vulnerability

1. **Contact us** by sending an email to **[security@getgrist.com](mailto:security@getgrist.com)** with the following information:
- A description of the vulnerability.
- Steps to reproduce the issue.
- Any known impacts or suggested fixes.

2. **Our response:**
- We will acknowledge your report within **three working days**.
- We will collaborate with you to verify and address the issue.
- Once resolved, we’ll release a patch and notify users.
1 change: 1 addition & 0 deletions buildtools/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ if [[ -e ext/buildtools/webpack.config.js ]]; then
fi

set -x
node buildtools/sanitize_translations.js
tsc --build $PROJECT
buildtools/update_type_info.sh app
webpack --config $WEBPACK_CONFIG --mode production
Expand Down
76 changes: 76 additions & 0 deletions buildtools/sanitize_translations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// This file should be run during build. It will go through all the translations in the static/locales
// directory, and pass every key and value through the sanitizer.

const fs = require('fs');
const path = require('path');
// Initialize purifier.
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
DOMPurify.addHook('uponSanitizeAttribute', handleSanitizeAttribute);
function handleSanitizeAttribute(node) {
if (!('target' in node)) { return; }
node.setAttribute('target', '_blank');
}

const directoryPath = readDirectoryPath();

const fileStream = fs.readdirSync(directoryPath)
.map((file) => path.join(directoryPath, file))
// Make sure it's a file
.filter((file) => fs.lstatSync(file).isFile())
// Make sure it is json file
.filter((file) => file.endsWith(".json"))
// Read the contents and put it into an array [path, json]
.map((file) => [file, JSON.parse(fs.readFileSync(file, "utf8"))]);

console.debug(`Found ${fileStream.length} files to sanitize`);

const sanitized = fileStream.map(([file, json]) => {
return [file, json, sanitizedJson(json)];
});

const onlyDifferent = sanitized.filter(([file, json, sanitizedJson]) => {
return JSON.stringify(json) !== JSON.stringify(sanitizedJson);
});

console.debug(`Found ${onlyDifferent.length} files that need sanitizing`);

// Write the sanitized json back to the files
onlyDifferent.forEach(([file, json, sanitizedJson]) => {
console.info(`Sanitizing ${file}`);
fs.writeFileSync(file, JSON.stringify(sanitizedJson, null, 4) + "\n");
});

console.info("Sanitization complete");

function sanitizedJson(json) {
// This is recursive function as some keys can be objects themselves, but all values are either
// strings or objects.
return Object.keys(json).reduce((acc, key) => {
const value = json[key];
if (typeof value === "string") {
acc[key] = purify(value);
} else if (typeof value === "object") {
acc[key] = sanitizedJson(value);
}
return acc;
}, {});
}


function readDirectoryPath() {
// Directory path is optional, it defaults to static/locales, but can be passed as an argument.
const args = process.argv.slice(2);
if (args.length > 1) {
console.error("Too many arguments, expected at most 1 argument.");
process.exit(1);
}
return args[0] || path.join(__dirname, "../static/locales");
}

function purify(inputString) {
// This removes any html tags from the string
return DOMPurify.sanitize(inputString);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "grist-core",
"version": "1.3.0",
"version": "1.3.2",
"license": "Apache-2.0",
"description": "Grist is the evolution of spreadsheets",
"homepage": "https://github.com/gristlabs/grist-core",
Expand Down
43 changes: 40 additions & 3 deletions static/locales/es.client.json
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,13 @@
"Grist signs user session cookies with a secret key. Please set this key via the environment variable GRIST_SESSION_SECRET. Grist falls back to a hard-coded default when it is not set. We may remove this notice in the future as session IDs generated since v1.1.16 are inherently cryptographically secure.": "Grist firma las cookies de sesión de usuario con una clave secreta. Establezca esta clave mediante la variable de entorno GRIST_SESSION_SECRET. Si no se establece, Grist vuelve a un valor predeterminado. Es posible que quitemos este aviso en el futuro, ya que los identificadores de sesión generados desde la versión 1.1.16 son intrínsecamente seguros desde el punto de vista criptográfico.",
"Enterprise": "Empresarial",
"Enable Grist Enterprise": "Activar Grist Enterprise",
"checking": "comprobando"
"checking": "comprobando",
"Audit Logs": "Registros de auditoría",
"{{firstDestinationName}} + {{- remainingDestinationsCount}} more": "{{firstDestinationName}} + {{- remainingDestinationsCount}} más",
"Log Streaming": "Transmisión de registros",
"New, Enterprise": "Nuevo, Empresa",
"Contact us": "Contáctenos",
"Off": "Apagar"
},
"CreateTeamModal": {
"Cancel": "Cancelar",
Expand Down Expand Up @@ -1737,7 +1743,7 @@
"Next step": "Paso siguiente",
"Skip step": "Omitir el paso",
"Skip tutorial": "Omitir el tutorial",
"Tell us who you are": "¿Quién eres?",
"Tell us who you are": "Cuéntanos quién eres",
"Type here": "Escribe aquí",
"Welcome": "Bienvenid@",
"What brings you to Grist (you can select multiple)?": "¿Qué te trae a Grist (puedes seleccionar varias opciones)?",
Expand All @@ -1760,7 +1766,8 @@
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Una clave de activación se utiliza para ejecutar Grist Enterprise después de un período de prueba\nde 30 días. Obtén una clave de activación [registrándose en Grist\nEmpresarial]({{signupLink}}). No necesitas una clave de activación para ejecutar\nGrist Core.\n\nMás información en nuestro [Centro de Ayuda]({{helpCenter}}).",
"Disable Grist Enterprise": "Desactivar Grist Enterprise",
"Enable Grist Enterprise": "Activar Grist Enterprise",
"Grist Enterprise is **enabled**.": "Grist Enterprise está **activado**."
"Grist Enterprise is **enabled**.": "Grist Enterprise está **activado**.",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [contacting us]({{contactLink}}) today. You do\nnot need an activation key to run Grist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Una clave de activación se utiliza para ejecutar Grist Enterprise después de un período de prueba\nde 30 días. Obtenga una clave de activación [poniéndose en contacto con nosotros]({{contactLink}}) hoy mismo. No\nnecesita una clave de activación para ejecutar Grist Core.\n\nMás información en nuestro [Centro de Ayuda]({{helpCenter}})."
},
"CustomWidgetGallery": {
"Add Widget": "Agregar widget",
Expand Down Expand Up @@ -1843,5 +1850,35 @@
"Record already assigned_one": "Registro ya asignado",
"Record already assigned_other": "Registro ya asignado",
"{{targetTable}} record {{targetName}} is already assigned to {{sourceTable}} record {{oldSourceName}}.": "{{targetTable}} registro {{targetName}} ya está asignado a {{sourceTable}} registro {{oldSourceName}}."
},
"AuditLogStreamingConfig": {
"Delete": "Borrar",
"Delete streaming destination?": "¿Borrar destino del streaming?",
"Destinations": "Destinos",
"Edit": "Editar",
"Edit streaming destination": "Editar el destino del streaming",
"Enter URL": "Introducir URL",
"Enter token": "Ingresar token",
"Learn more": "Más información",
"URL": "URL",
"Destination": "Destino",
"Add destination": "Añadir destino",
"Add streaming destination": "Agregar destino de transmisión",
"Cancel": "Cancelar",
"Are you sure you want to delete this streaming destination? This action cannot be undone.": "¿Está seguro de que desea eliminar este destino de streaming? Esta acción no se puede deshacer.",
"Other": "Otro",
"Splunk": "Splunk",
"Save": "Guardar",
"Start streaming": "Iniciar streaming",
"Token": "Token"
},
"AuditLogsPage": {
"Audit Logs": "Registros de auditoría",
"Audit logs for {{siteName}}": "Registros de auditoría para {{siteName}}",
"Contact us": "Contáctenos",
"Home": "Inicio",
"Log streaming": "Transmisión de registros",
"Only site owners may access audit logs.": "Solo los propietarios de las páginas pueden acceder a los registros de auditoría.",
"upgrade your plan": "Mejora tu plan"
}
}
2 changes: 1 addition & 1 deletion static/locales/eu.client.json
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@
"Section: ": "Atala: ",
"Advanced settings": "Ezarpen aurreratuak",
"Big tables may be marked as \"on-demand\" to avoid loading them into the data engine.": "Taula handiak \"nahieran\" gisa marka litezke datu-motorrean kargatzea saihesteko.",
"Compact": "Trinkotu",
"Compact": "Trinkoa",
"Edit Card Layout": "Editatu txartelen antolaketa",
"Make On-Demand": "Egin nahieran",
"Plugin: ": "Plugina: ",
Expand Down
26 changes: 26 additions & 0 deletions static/locales/hu.client.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"ACUserManager": {
"We'll email an invite to {{email}}": "Küldünk egy meghívó e-mailt ide: {{email}}",
"Enter email address": "Adja meg az e-mail címet",
"Invite new member": "Új tag meghívása"
},
"AccessRules": {
"Add User Attributes": "Új felhasználó attribútum",
"Everyone": "Mindenki",
"Default Rules": "Alapértelmezett szabályok",
"Invalid": "Érvénytelen",
"Add Table Rules": "Új táblázat szabály",
"Add Column Rule": "Új oszlop szabály",
"Add Default Rule": "Új alapértelmezett szabály",
"Attribute name": "Attribútum neve",
"Allow everyone to view Access Rules.": "Mindeki láthassa a hozzáférési szabályokat.",
"Attribute to Look Up": "Keresendő attribútum",
"Checking...": "Ellenőrzés…",
"Condition": "Feltétel",
"Delete Table Rules": "Táblázat szabályok törlése",
"Enter Condition": "Írja be a feltételt",
"Everyone Else": "Mindenki más",
"Lookup Column": "Keresési oszlop",
"Lookup Table": "Keresési táblázat"
}
}
8 changes: 8 additions & 0 deletions static/locales/hu.server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"sendAppPage": {
"Loading": "Töltés"
},
"oidc": {
"emailNotVerifiedError": "Kérem ellenőrizze az e-mail címet az azonosítási szolgáltatónál, és jelentkezzen be újra."
}
}
41 changes: 39 additions & 2 deletions static/locales/sk.client.json
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,13 @@
"Session Secret": "Tajomstvo Relácie",
"Enable Grist Enterprise": "Povoliť Grist Enterprise",
"Enterprise": "Enterprise",
"checking": "kontrola"
"checking": "kontrola",
"Contact us": "Kontaktujte nás",
"Log Streaming": "Streamovanie denníka",
"Audit Logs": "Denníky auditu",
"{{firstDestinationName}} + {{- remainingDestinationsCount}} more": "{{firstDestinationName}} + {{- remainingDestinationsCount}} viac",
"New, Enterprise": "Nové, Enterprise",
"Off": "Vypnúť"
},
"TimingPage": {
"Table ID": "ID Tabuľky",
Expand Down Expand Up @@ -1700,7 +1706,8 @@
"Disable Grist Enterprise": "Zakázať Grist Enterprise",
"Enable Grist Enterprise": "Povoliť Grist Enterprise",
"Grist Enterprise is **enabled**.": "Grist Enterprise je **povolený**.",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Aktivačný kľúč sa používa na spustenie Grist Enterprise po uplynutí skúšobnej\ndoby 30 dní. Získajte aktivačný kľúč [registráciou pre Grist\nPodnik]({{signupLink}}). Na spustenie nepotrebujete aktivačný kľúč\nGrist Core.\n\nZistite viac v našom [Help Center] ({{helpCenter}})."
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [signing up for Grist\nEnterprise]({{signupLink}}). You do not need an activation key to run\nGrist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Aktivačný kľúč sa používa na spustenie Grist Enterprise po uplynutí skúšobnej\ndoby 30 dní. Získajte aktivačný kľúč [registráciou pre Grist\nPodnik]({{signupLink}}). Na spustenie nepotrebujete aktivačný kľúč\nGrist Core.\n\nZistite viac v našom [Help Center] ({{helpCenter}}).",
"An activation key is used to run Grist Enterprise after a trial period\nof 30 days has expired. Get an activation key by [contacting us]({{contactLink}}) today. You do\nnot need an activation key to run Grist Core.\n\nLearn more in our [Help Center]({{helpCenter}}).": "Aktivačný klúč slúží na spustenie aplikace Grist Enterprise po skúšobnej dobe.\npo uplynutí 30dennej zkúšobnej dobe. Aktivačný klúč získate [kontaktujte nás]({{contactLink}}) ešte dnes.\nAktivačný klúč nepotrebujete na spustenie aplikáce Grist Core.\n\nViac informacií sa dozviete v našom [Centre nápovedy]({{helpCenter}})."
},
"ViewLayout": {
"Delete": "Odstrániť",
Expand Down Expand Up @@ -1790,5 +1797,35 @@
"Record already assigned_one": "Záznam je už priradený",
"Record already assigned_other": "Záznam je už priradený",
"{{targetTable}} record {{targetName}} is already assigned to {{sourceTable}} record {{oldSourceName}}.": "{{targetTable}} záznam {{targetName}} je už priradený k {{sourceTable}} záznam {{oldSourceName}}."
},
"AuditLogStreamingConfig": {
"Add destination": "Pridať cieľ",
"Add streaming destination": "Pridať cieľ streamingu",
"Are you sure you want to delete this streaming destination? This action cannot be undone.": "Naozaj chcete odstrániť tento cieľ streamovania? Túto akciu nie je možné vrátiť späť.",
"Cancel": "Zrušiť",
"Delete": "Zmazať",
"Delete streaming destination?": "Zmazať cieľ streamingu?",
"Destination": "Cieľ",
"Destinations": "Ciele",
"Edit": "Zmeniť",
"Edit streaming destination": "Zmeniť cieľ streamingu",
"Enter URL": "Zadať URL",
"Enter token": "Zadať token",
"Learn more": "Ďaľšie informácie",
"Save": "Uložiť",
"Splunk": "Splunk",
"Start streaming": "Spustiť streaming",
"Token": "Token",
"URL": "URL",
"Other": "Ostatné"
},
"AuditLogsPage": {
"Contact us": "Kontaktujte nás",
"Home": "Domov",
"Log streaming": "Streaming logov",
"Only site owners may access audit logs.": "Ku denníkom auditu môžu pristupovať iba vlastníci stránok.",
"upgrade your plan": "aktualizovať svoj plán",
"Audit logs for {{siteName}}": "Záznami auditu pre {{siteName}}",
"Audit Logs": "Záznami auditu"
}
}

0 comments on commit 72a8412

Please sign in to comment.