(core) updates from grist-core

pull/743/head
Paul Fitzpatrick 6 months ago
commit 68801474b1

@ -68,6 +68,11 @@ export interface SessionObj {
// anonymous editing (e.g. to allow the user to edit
// something they just added, without allowing the suer
// to edit other people's contributions).
oidc?: {
// codeVerifier is used during OIDC authentication, to protect against attacks like CSRF.
codeVerifier?: string;
}
}
// Make an artificial change to a session to encourage express-session to set a cookie.

@ -214,6 +214,8 @@ async function removeData(filename: string) {
for (const tableId of tableIds) {
await db.run(`DELETE FROM ${quoteIdent(tableId)}`);
}
await db.run(`DELETE FROM _grist_Attachments`);
await db.run(`DELETE FROM _gristsys_Files`);
await db.close();
}

@ -0,0 +1,187 @@
/**
* Configuration for OpenID Connect (OIDC), useful for enterprise single-sign-on logins.
* A good informative overview of OIDC is at https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc
* Note:
* SP is "Service Provider", in our case, the Grist application.
* IdP is the "Identity Provider", somewhere users log into, e.g. Okta or Google Apps.
*
* We also use optional attributes for the user's name, for which we accept any of:
* given_name
* family_name
*
* Expected environment variables:
* env GRIST_OIDC_SP_HOST=https://<your-domain>
* Host at which our /oauth2 endpoint will live. Optional, defaults to `APP_HOME_URL`.
* env GRIST_OIDC_IDP_ISSUER
* The issuer URL for the IdP, passed to node-openid-client, see: https://github.com/panva/node-openid-client/blob/a84d022f195f82ca1c97f8f6b2567ebcef8738c3/docs/README.md#issuerdiscoverissuer.
* This variable turns on the OIDC login system.
* env GRIST_OIDC_IDP_CLIENT_ID
* The client ID for the application, as registered with the IdP.
* env GRIST_OIDC_IDP_CLIENT_SECRET
* The client secret for the application, as registered with the IdP.
* env GRIST_OIDC_IDP_SCOPES
* The scopes to request from the IdP, as a space-separated list. Defaults to "openid email profile".
*
* This version of OIDCConfig has been tested with Keycloak OIDC IdP following the instructions
* at:
* https://www.keycloak.org/getting-started/getting-started-docker
*
* /!\ CAUTION: For production, be sure to use https for all URLs. /!\
*
* For development of this module on localhost, these settings should work:
* - GRIST_OIDC_SP_HOST=http://localhost:8484 (or whatever port you use for Grist)
* - GRIST_OIDC_IDP_ISSUER=http://localhost:8080/realms/myrealm (replace 8080 by the port you use for keycloak)
* - GRIST_OIDC_IDP_CLIENT_ID=my_grist_instance
* - GRIST_OIDC_IDP_CLIENT_SECRET=YOUR_SECRET (as set in keycloak)
* - GRIST_OIDC_IDP_SCOPES="openid email profile"
*/
import * as express from 'express';
import { GristLoginSystem, GristServer } from './GristServer';
import { Client, generators, Issuer, UserinfoResponse } from 'openid-client';
import { Sessions } from './Sessions';
import log from 'app/server/lib/log';
import { appSettings } from './AppSettings';
import { RequestWithLogin } from './Authorizer';
const CALLBACK_URL = '/oauth2/callback';
export class OIDCConfig {
private _client: Client;
private _redirectUrl: string;
public constructor() {
}
public async initOIDC(): Promise<void> {
const section = appSettings.section('login').section('system').section('oidc');
const spHost = section.flag('spHost').requireString({
envVar: 'GRIST_OIDC_SP_HOST',
defaultValue: process.env.APP_HOME_URL,
});
const issuerUrl = section.flag('issuer').requireString({
envVar: 'GRIST_OIDC_IDP_ISSUER',
});
const clientId = section.flag('clientId').requireString({
envVar: 'GRIST_OIDC_IDP_CLIENT_ID',
});
const clientSecret = section.flag('clientSecret').requireString({
envVar: 'GRIST_OIDC_IDP_CLIENT_SECRET',
censor: true,
});
const issuer = await Issuer.discover(issuerUrl);
this._redirectUrl = new URL(CALLBACK_URL, spHost).href;
this._client = new issuer.Client({
client_id: clientId,
client_secret: clientSecret,
redirect_uris: [ this._redirectUrl ],
response_types: [ 'code' ],
});
}
public addEndpoints(app: express.Application, sessions: Sessions): void {
app.get(CALLBACK_URL, this.handleCallback.bind(this, sessions));
}
public async handleCallback(sessions: Sessions, req: express.Request, res: express.Response): Promise<void> {
try {
const params = this._client.callbackParams(req);
const { state } = params;
if (!state) {
throw new Error('Login or logout failed to complete');
}
const codeVerifier = await this._retrieveCodeVerifierFromSession(req);
const tokenSet = await this._client.callback(
this._redirectUrl,
params,
{ state, code_verifier: codeVerifier }
);
const userInfo = await this._client.userinfo(tokenSet);
const profile = this._makeUserProfileFromUserInfo(userInfo);
const scopedSession = sessions.getOrCreateSessionFromRequest(req);
await scopedSession.operateOnScopedSession(req, async (user) => Object.assign(user, {
profile,
}));
res.redirect('/');
} catch (err) {
log.error(`OIDC callback failed: ${err.message}`);
res.status(500).send(`OIDC callback failed: ${err.message}`);
}
}
public async getLoginRedirectUrl(req: express.Request): Promise<string> {
const codeVerifier = await this._generateAndStoreCodeVerifier(req);
const codeChallenge = generators.codeChallenge(codeVerifier);
const state = generators.state();
const authUrl = this._client.authorizationUrl({
scope: process.env.GRIST_OIDC_IDP_SCOPES || 'openid email profile',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
state,
});
return authUrl;
}
public async getLogoutRedirectUrl(req: express.Request, redirectUrl: URL): Promise<string> {
return this._client.endSessionUrl({
post_logout_redirect_uri: redirectUrl.href
});
}
private async _generateAndStoreCodeVerifier(req: express.Request) {
const mreq = req as RequestWithLogin;
if (!mreq.session) { throw new Error('no session available'); }
const codeVerifier = generators.codeVerifier();
mreq.session.oidc = {
codeVerifier,
};
return codeVerifier;
}
private async _retrieveCodeVerifierFromSession(req: express.Request) {
const mreq = req as RequestWithLogin;
if (!mreq.session) { throw new Error('no session available'); }
const codeVerifier = mreq.session.oidc?.codeVerifier;
if (!codeVerifier) { throw new Error('Login is stale'); }
delete mreq.session.oidc?.codeVerifier;
return codeVerifier;
}
private _makeUserProfileFromUserInfo(userInfo: UserinfoResponse) {
const email = userInfo.email;
const fname = userInfo.given_name ?? '';
const lname = userInfo.family_name ?? '';
return {
email,
name: `${fname} ${lname}`.trim(),
};
}
}
export async function getOIDCLoginSystem(): Promise<GristLoginSystem|undefined> {
if (!process.env.GRIST_OIDC_IDP_ISSUER) { return undefined; }
return {
async getMiddleware(gristServer: GristServer) {
const config = new OIDCConfig();
await config.initOIDC();
return {
getLoginRedirectUrl: config.getLoginRedirectUrl.bind(config),
getSignUpRedirectUrl: config.getLoginRedirectUrl.bind(config),
getLogoutRedirectUrl: config.getLogoutRedirectUrl.bind(config),
async addEndpoints(app: express.Express) {
config.addEndpoints(app, gristServer.getSessions());
return 'oidc';
},
};
},
async deleteUser() {},
};
}

@ -1,6 +1,6 @@
{
"name": "grist-core",
"version": "1.1.6",
"version": "1.1.7",
"license": "Apache-2.0",
"description": "Grist is the evolution of spreadsheets",
"homepage": "https://github.com/gristlabs/grist-core",
@ -168,6 +168,7 @@
"multiparty": "4.2.2",
"node-abort-controller": "3.0.1",
"node-fetch": "2.6.7",
"openid-client": "^5.6.1",
"pg": "8.6.0",
"piscina": "3.2.0",
"plotly.js-basic-dist": "2.13.2",

@ -21,9 +21,9 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
export NODE_PATH=_build:_build/core:_build/stubs:_build/ext
source $SCRIPT_DIR/get_checkpoint_path.sh
if [[ -z "GRIST_CHECKPOINT" ]]; then
if [[ -z "$GRIST_CHECKPOINT" ]]; then
echo "Skipping checkpoint generation"
return
exit 0
fi
export GRIST_CHECKPOINT_MAKE=1

@ -1,6 +1,6 @@
# This number should be bumped up if making a non-additive change
# to python packages.
GRIST_PYODIDE_VERSION = 2
GRIST_PYODIDE_VERSION = 3
default:
echo "Welcome to the pyodide sandbox"

@ -1,6 +1,6 @@
[
"astroid-2.14.2-cp311-none-any.whl",
"asttokens-2.2.1-cp311-none-any.whl",
"asttokens-2.4.0-cp311-none-any.whl",
"chardet-5.1.0-cp311-none-any.whl",
"et_xmlfile-1.0.1-cp311-none-any.whl",
"executing-1.1.1-cp311-none-any.whl",

@ -0,0 +1,86 @@
{
"AccessRules": {
"Permission to access the document in full when needed": "الإذن بالنفاذ إلى المستند بالكامل عند الحاجة",
"Permissions": "الأذون",
"Type a message...": "اكتب رسالة…",
"Allow editors to edit structure (e.g. modify and delete tables, columns, layouts), and to write formulas, which give access to all data regardless of read restrictions.": "السماح للمحررين بتحرير البنية (أي التعديل والحذف في الجداول والأعمدة والترتيبات)، وكتابة الصيغ الرياضية، وهذا يجعلهم نافذين إلى كل البيانات بغض النظر عن قيود القراءة.",
"Save": "حفظ"
},
"AccountPage": {
"Theme": "السمة",
"Change Password": "تغيير كلمة السر",
"Password & Security": "كلمة السر والأمان",
"Account settings": "إعدادات الحساب",
"Two-factor authentication": "المصادقة ذات العاملين",
"Two-factor authentication is an extra layer of security for your Grist account designed to ensure that you're the only person who can access your account, even if someone knows your password.": "المصادقة ذات العاملين Two-factor authentication طبقة إضافية من الحماية لحسابك في Grista مصممة للتأكد من أنك الشخص الوحيد القادر على النفاذ إلى حسابك، حتى لو كان شخص آخر يعرف كلمة السر خاصتك.",
"Language": "اللغة",
"Edit": "تحرير",
"Login Method": "طريقة الدخول",
"Allow signing in to this account with Google": "السماح بالدخول إلى هذا الحساب باستخدام Google",
"Save": "حفظ"
},
"AccountWidget": {
"Add Account": "إضافة حساب",
"Switch Accounts": "تبديل الحساب",
"Activation": "التفعيل",
"Support Grist": "ادعم Grist",
"Upgrade Plan": "ترقية الخطة",
"Sign Out": "خروج",
"Profile Settings": "إعدادات الملف الشخصي",
"Sign in": "دخول",
"Pricing": "التسعير",
"Use This Template": "استعمل هذا القالب",
"Billing Account": "حساب الفوترة",
"Sign In": "دخول",
"Accounts": "الحسابات",
"Sign Up": "خروج"
},
"ACUserManager": {
"Invite new member": "دعوة عضو جديد",
"We'll email an invite to {{email}}": "سنرسل دعوة إلى البريد الإلكتروني {{email}}",
"Enter email address": "أدخل عنوان البريد الإلكتروني"
},
"ApiKey": {
"Click to show": "انقر لتعرض"
},
"ChartView": {
"Pick a column": "اختر عمودا"
},
"CellContextMenu": {
"Insert row below": "إدراج صف تحته",
"Copy": "نسخ",
"Delete {{count}} columns_other": "حذف {{count}} من الأعمدة",
"Insert row above": "إدراج صف فوقه",
"Delete {{count}} rows_other": "حذف {{count}} من الصفوف",
"Comment": "تعليق",
"Insert column to the right": "إدراج عمود إلى اليمين",
"Cut": "قص",
"Insert column to the left": "إدراج عمود إلى اليسار",
"Paste": "لصق"
},
"ColumnFilterMenu": {
"No matching values": "لا قيم مطابقة"
},
"ColorSelect": {
"Apply": "تطبيق",
"Cancel": "إلغاء"
},
"AppHeader": {
"Personal Site": "الموقع الشخصي",
"Home Page": "الصفحة الرئيسية",
"Team Site": "موقع الفريق",
"Grist Templates": "قوالب Grist"
},
"CustomSectionConfig": {
" (optional)": " (اختياري)"
},
"DataTables": {
"Click to copy": "انقر لتنسخ"
},
"DocHistory": {
"Activity": "النشاط"
},
"AppModel": {
"This team site is suspended. Documents can be read, but not modified.": "موقع الفريق هذا معلق. يمكن قراءة المستندات لكن لا يمكن تعديلها."
}
}

@ -0,0 +1,27 @@
{
"AccessRules": {
"Add Column Rule": "Přidej Sloupcové Pravidlo",
"Lookup Column": "Vyhledávací Sloupec",
"Enter Condition": "Napiš Podmínku",
"Everyone Else": "Všichni Ostatní",
"Allow everyone to view Access Rules.": "Umožni všem zobrazit Přístupové Práva.",
"Lookup Table": "Vyhledávací Tabulka",
"Add Table Rules": "Přidej Tabulkové Pravidlo",
"Invalid": "Neplatné",
"Condition": "Podmínka",
"Delete Table Rules": "Vymaž Tabulkové Pravidla",
"Default Rules": "Základní Práva",
"Attribute name": "Jméno Atributu",
"Add User Attributes": "Přidej Uživatelské Atributy",
"Attribute to Look Up": "Atribut k Vyhledání",
"Everyone": "Všichni",
"Allow everyone to copy the entire document, or view it in full in fiddle mode.\nUseful for examples and templates, but not for sensitive data.": "Umožni všem kopírovat celý dokument, nebo zobrazit plně v \"fiddle\" režimu.\nUžiitečné pro ukázky a šablony, ale ne pro citlivá data.",
"Add Default Rule": "Přidej Základní Pravidlo",
"Checking...": "Kontroluji…"
},
"ACUserManager": {
"Invite new member": "Pozvi nového uživatele",
"We'll email an invite to {{email}}": "Zašleme pozvánku emailem na {{email}}",
"Enter email address": "Napiš e-mailovou adresu"
}
}

@ -1055,7 +1055,8 @@
},
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "A UUID is a randomly-generated string that is useful for unique identifiers and link keys.",
"Lookups return data from related tables.": "Lookups return data from related tables.",
"Use reference columns to relate data in different tables.": "Use reference columns to relate data in different tables."
"Use reference columns to relate data in different tables.": "Use reference columns to relate data in different tables.",
"You can choose from widgets available to you in the dropdown, or embed your own by providing its full URL.": "You can choose from widgets available to you in the dropdown, or embed your own by providing its full URL."
},
"DescriptionConfig": {
"DESCRIPTION": "DESCRIPTION"

@ -1109,7 +1109,8 @@
"Can't find the right columns? Click 'Change Widget' to select the table with events data.": "¿No encuentras las columnas adecuadas? Haz clic en \"Cambiar widget\" para seleccionar la tabla con los datos de los eventos.",
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "Un UUID es una cadena generada aleatoriamente que resulta útil para identificadores únicos y claves de los enlaces.",
"Lookups return data from related tables.": "Las búsquedas devuelven datos de tablas relacionadas.",
"Use reference columns to relate data in different tables.": "Utilizar las columnas de referencia para relacionar los datos de distintas tablas."
"Use reference columns to relate data in different tables.": "Utilizar las columnas de referencia para relacionar los datos de distintas tablas.",
"You can choose from widgets available to you in the dropdown, or embed your own by providing its full URL.": "Puedes elegir entre los widgets disponibles en el menú desplegable, o incrustar el suyo propio proporcionando su dirección URL completa."
},
"DescriptionConfig": {
"DESCRIPTION": "DESCRIPCIÓN"

@ -557,7 +557,8 @@
"Search columns": "Поисковые столбцы",
"Timestamp": "Метка времени",
"Adding UUID column": "Добавление столбца UUID",
"Adding duplicates column": "Добавление столбца дубликатов"
"Adding duplicates column": "Добавление столбца дубликатов",
"Lookups": "Lookups"
},
"FilterBar": {
"SearchColumns": "Столбцы поиска",
@ -1052,7 +1053,9 @@
},
"Calendar": "Календарь",
"Can't find the right columns? Click 'Change Widget' to select the table with events data.": "Не можете найти нужные столбцы? Нажмите «Изменить виджет», чтобы выбрать таблицу с данными о событиях.",
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "UUID - это случайно сгенерированная строка, которая полезна для уникальных идентификаторов и ключевых ссылок."
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "UUID - это случайно сгенерированная строка, которая полезна для уникальных идентификаторов и ключевых ссылок.",
"Lookups return data from related tables.": "Lookups возвращают данные из связанных таблиц.",
"Use reference columns to relate data in different tables.": "Используйте ссылочные столбцы для сопоставления данных в разных таблицах."
},
"DescriptionConfig": {
"DESCRIPTION": "ОПИСАНИЕ"

@ -75,7 +75,7 @@
"Toggle Mobile Mode": "Preklapljanje mobilnega načina",
"Activation": "Aktivacija",
"Billing Account": "Račun za zaračunavanje",
"Support Grist": "Podpora Grist",
"Support Grist": "Grist podpora",
"Upgrade Plan": "Načrt nadgradnje",
"Sign In": "Prijavi se",
"Use This Template": "Uporabite to predlogo",
@ -176,7 +176,7 @@
"Examples & Templates": "Primeri & predloge"
},
"GridViewMenus": {
"Rename column": "Preimenovanje stolpca",
"Rename column": "Preimenuj stolpec",
"Delete {{count}} columns_one": "Brisanje stolpca",
"Delete {{count}} columns_other": "Brisanje stolpcev {{count}}",
"Unfreeze {{count}} columns_one": "Odmrzni ta stolpec",
@ -185,12 +185,12 @@
"Freeze {{count}} columns_other": "Zamrznite {{count}} stolpcev",
"Show column {{- label}}": "Prikaži stolpec {{- label}}",
"Sort": "Razvrsti",
"Column Options": "Možnosti stolpcev",
"Column Options": "Možnosti stolpca",
"Filter Data": "Filtriranje podatkov",
"Hide {{count}} columns_other": "Skrij {{count}} stolpcev",
"Add Column": "Dodaj stolpec",
"Reset {{count}} columns_one": "Ponastavitev stolpca",
"Freeze {{count}} columns_one": "Zamrznite ta stolpec",
"Freeze {{count}} columns_one": "Zamrzni stolpec",
"More sort options ...": "Več možnosti razvrščanja…",
"Freeze {{count}} more columns_one": "Zamrznite še en stolpec",
"Reset {{count}} columns_other": "Ponastavi {{count}} stolpcev",
@ -229,7 +229,7 @@
},
"HomeLeftPane": {
"Trash": "Koš",
"Rename": "Preimenovanje",
"Rename": "Preimenuj",
"Delete": "Izbriši",
"Delete {{workspace}} and all included documents?": "Izbriši {{workspace}} in vse vključene dokumente?",
"All Documents": "Vsi dokumenti",
@ -277,7 +277,7 @@
"Return to viewing as yourself": "Vrnite se k ogledu kot vi"
},
"pages": {
"Rename": "Preimenovanje",
"Rename": "Preimenuj",
"Duplicate Page": "Podvojena stran",
"You do not have edit access to this document": "Nimate dovoljenja za urejanje tega dokumenta",
"Remove": "Odstrani"
@ -290,7 +290,7 @@
"Search": "Iskanje"
},
"AddNewButton": {
"Add New": "Dodaj novo"
"Add New": "Dodaj"
},
"DataTables": {
"Delete {{formattedTableName}} data, and remove it from all pages?": "Izbrišite podatke {{formattedTableName}} in jih odstranite z vseh strani?",
@ -642,7 +642,7 @@
"Access rules give you the power to create nuanced rules to determine who can see or edit which parts of your document.": "Pravila dostopa vam omogočajo, da ustvarite podrobna pravila, s katerimi določite, kdo lahko vidi ali ureja posamezne dele dokumenta.",
"Rearrange the fields in your card by dragging and resizing cells.": "Z vlečenjem in spreminjanjem velikosti polj na kartici spremenite njihovo razporeditev.",
"Useful for storing the timestamp or author of a new record, data cleaning, and more.": "Uporabno za shranjevanje časovnega žiga ali avtorja novega zapisa, čiščenje podatkov in drugo.",
"Click the Add New button to create new documents or workspaces, or import data.": "Če želite ustvariti nove dokumente ali delovne prostore ali uvoziti podatke, kliknite gumb Dodaj novo.",
"Click the Add New button to create new documents or workspaces, or import data.": "Če želite ustvariti nove dokumente ali delovne prostore ali uvoziti podatke, kliknite gumb Dodaj.",
"Nested Filtering": "Vgnezdeno filtriranje",
"Only those rows will appear which match all of the filters.": "Prikazane bodo samo tiste vrstice, ki ustrezajo vsem filtrom.",
"Editing Card Layout": "Urejanje postavitve kartice",
@ -677,7 +677,8 @@
"Cells in a reference column always identify an {{entire}} record in that table, but you may select which column from that record to show.": "Celice v referenčnem stolpcu vedno identificirajo {{entire}} zapis v tej tabeli, vendar lahko izberete, kateri stolpec iz tega zapisa želite prikazati.",
"A UUID is a randomly-generated string that is useful for unique identifiers and link keys.": "UUID je naključno ustvarjen niz, ki je uporaben za edinstvene identifikatorje in ključe povezav.",
"Lookups return data from related tables.": "Iskanje vrne podatke iz povezanih tabel.",
"Use reference columns to relate data in different tables.": "Uporabite referenčne stolpce za povezavo podatkov v različnih tabelah."
"Use reference columns to relate data in different tables.": "Uporabite referenčne stolpce za povezavo podatkov v različnih tabelah.",
"You can choose from widgets available to you in the dropdown, or embed your own by providing its full URL.": "Izbirate lahko med pripomočki, ki so vam na voljo v spustnem meniju, ali vdelate svojega tako, da navedete njegov polni URL."
},
"UserManager": {
"Anyone with link ": "Vsakdo s povezavo ",
@ -1124,7 +1125,7 @@
"Customizing columns": "Prilagajanje stolpcev",
"Double-click or hit {{enter}} on a cell to edit it. ": "Dvokliknite ali pritisnite {{enter}} na celico, da jo uredite. ",
"Welcome to Grist!": "Dobrodošli v Gristu!",
"Add New": "Dodaj novo",
"Add New": "Dodaj",
"Toggle the {{creatorPanel}} to format columns, ": "Preklopite {{creatorPanel}} za oblikovanje stolpcev, ",
"convert to card view, select data, and more.": "pretvorite v pogled kartice, izberite podatke in drugo.",
"Building up": "Gradnja",

File diff suppressed because it is too large Load Diff

@ -19,7 +19,7 @@
"Add Default Rule": "添加默认规则",
"Add Table Rules": "添加表格规则",
"Add User Attributes": "添加用户属性",
"Allow everyone to copy the entire document, or view it in full in fiddle mode.\nUseful for examples and templates, but not for sensitive data.": "允许每个人复制整个文档,或在演示模式下完整查看。\n适用于示例和模板但不要用在有敏感数据的情况下。",
"Allow everyone to copy the entire document, or view it in full in fiddle mode.\nUseful for examples and templates, but not for sensitive data.": "允许所有人复制整个文档,或在演示模式下完整查看。\n适用于示例和模板但不适用于包含敏感数据的文档。",
"Attribute name": "属性名称",
"Condition": "条件",
"Default Rules": "默认规则",
@ -144,7 +144,7 @@
"Cut": "剪切"
},
"ACUserManager": {
"Enter email address": "请输入电邮地址",
"Enter email address": "请输入电地址",
"Invite new member": "邀请新成员",
"We'll email an invite to {{email}}": "我们将通过电子邮件向 {{email}} 发送邀请"
},

@ -1,10 +1,12 @@
import { getForwardAuthLoginSystem } from 'app/server/lib/ForwardAuthLogin';
import { GristLoginSystem } from 'app/server/lib/GristServer';
import { getMinimalLoginSystem } from 'app/server/lib/MinimalLogin';
import { getOIDCLoginSystem } from 'app/server/lib/OIDCConfig';
import { getSamlLoginSystem } from 'app/server/lib/SamlConfig';
export async function getLoginSystem(): Promise<GristLoginSystem> {
return await getSamlLoginSystem() ||
await getOIDCLoginSystem() ||
await getForwardAuthLoginSystem() ||
await getMinimalLoginSystem();
}

@ -133,7 +133,7 @@ describe('ActionLog', function() {
assert.equal(await gu.getActiveCell().getText(), 'f');
// Delete Table1Renamed.
await gu.removeTable('Table1Renamed');
await gu.removeTable('Table1Renamed', {dismissTips: true});
await driver.findContent('.action_log label', /All tables/).find('input').click();
const item4 = await getActionLogItem(4);

@ -454,7 +454,7 @@ describe('ChoiceList', function() {
it('should allow ChoiceList conversions for column used in summary', async function() {
// Add a widget with a summary on column A.
await gu.addNewSection(/Table/, /Table1/, {summarize: [/^A$/]});
await gu.addNewSection(/Table/, /Table1/, {dismissTips: true, summarize: [/^A$/]});
await testTextChoiceListConversions();
await gu.undo();
});

@ -1251,8 +1251,9 @@ export async function renameColumn(col: IColHeader|string, newName: string) {
/**
* Removes a table using RAW data view.
*/
export async function removeTable(tableId: string) {
export async function removeTable(tableId: string, options: {dismissTips?: boolean} = {}) {
await driver.find(".test-tools-raw").click();
if (options.dismissTips) { await dismissBehavioralPrompts(); }
const tableIdList = await driver.findAll('.test-raw-data-table-id', e => e.getText());
const tableIndex = tableIdList.indexOf(tableId);
assert.isTrue(tableIndex >= 0, `No raw table with id ${tableId}`);

@ -4923,6 +4923,11 @@ jest-worker@^27.4.5:
merge-stream "^2.0.0"
supports-color "^8.0.0"
jose@^4.15.1:
version "4.15.4"
resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.4.tgz#02a9a763803e3872cf55f29ecef0dfdcc218cc03"
integrity sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==
joycon@^3.0.1:
version "3.1.1"
resolved "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz"
@ -6067,6 +6072,11 @@ object-assign@^4.0.1, object-assign@^4.1.1:
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-hash@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
object-inspect@^1.9.0:
version "1.9.0"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz"
@ -6087,6 +6097,11 @@ object.assign@^4.0.4:
has-symbols "^1.0.3"
object-keys "^1.1.1"
oidc-token-hash@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz#9a229f0a1ce9d4fc89bcaee5478c97a889e7b7b6"
integrity sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@ -6113,6 +6128,16 @@ once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
dependencies:
wrappy "1"
openid-client@^5.6.1:
version "5.6.1"
resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.6.1.tgz#8f7526a50c290a5e28a7fe21b3ece3107511bc73"
integrity sha512-PtrWsY+dXg6y8mtMPyL/namZSYVz8pjXz3yJiBNZsEdCnu9miHLB4ELVC85WvneMKo2Rg62Ay7NkuCpM0bgiLQ==
dependencies:
jose "^4.15.1"
lru-cache "^6.0.0"
object-hash "^2.2.0"
oidc-token-hash "^5.0.3"
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz"

Loading…
Cancel
Save