From c608fd4541edf7798fa27bd94f26c82e8d1c64ea Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 9 Jan 2025 14:10:13 -0600 Subject: [PATCH 1/3] move query generator page --- .../{admin => query-generator}/get-llm-generated-sql.js | 0 .../{admin => query-generator}/view-query-generator.js | 0 website/assets/js/cloud.setup.js | 2 +- website/config/routes.js | 4 ++-- website/views/layouts/layout.ejs | 3 ++- 5 files changed, 5 insertions(+), 4 deletions(-) rename website/api/controllers/{admin => query-generator}/get-llm-generated-sql.js (100%) rename website/api/controllers/{admin => query-generator}/view-query-generator.js (100%) diff --git a/website/api/controllers/admin/get-llm-generated-sql.js b/website/api/controllers/query-generator/get-llm-generated-sql.js similarity index 100% rename from website/api/controllers/admin/get-llm-generated-sql.js rename to website/api/controllers/query-generator/get-llm-generated-sql.js diff --git a/website/api/controllers/admin/view-query-generator.js b/website/api/controllers/query-generator/view-query-generator.js similarity index 100% rename from website/api/controllers/admin/view-query-generator.js rename to website/api/controllers/query-generator/view-query-generator.js diff --git a/website/assets/js/cloud.setup.js b/website/assets/js/cloud.setup.js index a8c3aaac405a..fd306f81fa6e 100644 --- a/website/assets/js/cloud.setup.js +++ b/website/assets/js/cloud.setup.js @@ -13,7 +13,7 @@ Cloud.setup({ /* eslint-disable */ - methods: {"redirectToStripeBillingPortal":{"verb":"GET","url":"/customers/update-subscription","args":[]},"downloadSitemap":{"verb":"GET","url":"/sitemap.xml","args":[]},"downloadRssFeed":{"verb":"GET","url":"/rss/:categoryName","args":["categoryName"]},"receiveUsageAnalytics":{"verb":"POST","url":"/api/v1/webhooks/receive-usage-analytics","args":["anonymousIdentifier","fleetVersion","licenseTier","numHostsEnrolled","numUsers","numTeams","numPolicies","numLabels","softwareInventoryEnabled","vulnDetectionEnabled","systemUsersEnabled","hostsStatusWebHookEnabled","numWeeklyActiveUsers","numWeeklyPolicyViolationDaysActual","numWeeklyPolicyViolationDaysPossible","hostsEnrolledByOperatingSystem","hostsEnrolledByOrbitVersion","hostsEnrolledByOsqueryVersion","storedErrors","numHostsNotResponding","organization","mdmMacOsEnabled","mdmWindowsEnabled","liveQueryDisabled","hostExpiryEnabled","numSoftwareVersions","numHostSoftwares","numSoftwareTitles","numHostSoftwareInstalledPaths","numSoftwareCPEs","numSoftwareCVEs","aiFeaturesDisabled","maintenanceWindowsEnabled","maintenanceWindowsConfigured","numHostsFleetDesktopEnabled","numQueries"]},"receiveFromGithub":{"verb":"GET","url":"/api/v1/webhooks/github","args":["botSignature","action","sender","repository","changes","issue","comment","pull_request","label","release"]},"receiveFromStripe":{"verb":"POST","url":"/api/v1/webhooks/receive-from-stripe","args":["id","type","data","webhookSecret"]},"getEstDeviceCertificate":{"verb":"POST","url":"/api/v1/get-est-device-certificate","args":["csrData","authToken"]},"deliverContactFormMessage":{"verb":"POST","url":"/api/v1/deliver-contact-form-message","args":["emailAddress","firstName","lastName","message"]},"sendPasswordRecoveryEmail":{"verb":"POST","url":"/api/v1/entrance/send-password-recovery-email","args":["emailAddress"]},"signup":{"verb":"POST","url":"/api/v1/customers/signup","args":["emailAddress","password","organization","firstName","lastName","signupReason"]},"updateProfile":{"verb":"POST","url":"/api/v1/account/update-profile","args":["firstName","lastName","organization","emailAddress"]},"updatePassword":{"verb":"POST","url":"/api/v1/account/update-password","args":["oldPassword","newPassword"]},"updateBillingCard":{"verb":"POST","url":"/api/v1/account/update-billing-card","args":["stripeToken","billingCardLast4","billingCardBrand","billingCardExpMonth","billingCardExpYear"]},"login":{"verb":"POST","url":"/api/v1/customers/login","args":["emailAddress","password","rememberMe"]},"logout":{"verb":"GET","url":"/api/v1/account/logout","args":[]},"createQuote":{"verb":"POST","url":"/api/v1/customers/create-quote","args":["numberOfHosts"]},"saveBillingInfoAndSubscribe":{"verb":"POST","url":"/api/v1/customers/save-billing-info-and-subscribe","args":["quoteId","organization","firstName","lastName","paymentSource"]},"updatePasswordAndLogin":{"verb":"POST","url":"/api/v1/entrance/update-password-and-login","args":["password","token"]},"deliverDemoSignup":{"verb":"POST","url":"/api/v1/deliver-demo-signup","args":["emailAddress"]},"createOrUpdateOneNewsletterSubscription":{"verb":"POST","url":"/api/v1/create-or-update-one-newsletter-subscription","args":["emailAddress"]},"unsubscribeFromAllNewsletters":{"verb":"GET","url":"/api/v1/unsubscribe-from-all-newsletters","args":["emailAddress"]},"buildLicenseKey":{"verb":"POST","url":"/api/v1/admin/build-license-key","args":["numberOfHosts","organization","expiresAt","partnerName"]},"createVantaAuthorizationRequest":{"verb":"POST","url":"/api/v1/create-vanta-authorization-request","args":["emailAddress","fleetInstanceUrl","fleetApiKey","redirectToExternalPageAfterAuthorization","sharedSecret"]},"redirectVantaAuthorizationRequest":{"verb":"GET","url":"/redirect-vanta-authorization-request","args":["vantaSourceId","state","vantaAuthorizationRequestURL","redirectAfterSetup"]},"deliverMdmBetaSignup":{"verb":"POST","url":"/api/v1/deliver-mdm-beta-signup","args":["emailAddress","fullName","jobTitle","numberOfHosts"]},"getHumanInterpretationFromOsquerySql":{"verb":"POST","url":"/api/v1/get-human-interpretation-from-osquery-sql","args":["sql"]},"deliverAppleCsr":{"verb":"POST","url":"/api/v1/deliver-apple-csr","args":["unsignedCsrData","deliveryMethod"]},"deliverMdmDemoEmail":{"verb":"POST","url":"/api/v1/deliver-mdm-demo-email","args":["emailAddress"]},"provisionSandboxInstanceAndDeliverEmail":{"verb":"POST","url":"/api/v1/admin/provision-sandbox-instance-and-deliver-email","args":["userId"]},"deliverTalkToUsFormSubmission":{"verb":"POST","url":"/api/v1/deliver-talk-to-us-form-submission","args":["emailAddress","firstName","lastName","organization","numberOfHosts","primaryBuyingSituation"]},"saveQuestionnaireProgress":{"verb":"POST","url":"/api/v1/save-questionnaire-progress","args":["currentStep","formData"]},"updateStartCtaVisibility":{"verb":"POST","url":"/api/v1/account/update-start-cta-visibility","args":[]},"deliverDealRegistrationSubmission":{"verb":"POST","url":"/api/v1/deliver-deal-registration-submission","args":["submittersFirstName","submittersLastName","submittersEmailAddress","submittersOrganization","customersFirstName","customersLastName","customersEmailAddress","linkedinUrl","customersOrganization","customersCurrentMdm","otherMdmEvaluated","preferredHosting","expectedDealSize","expectedCloseDate","notes"]},"unsubscribeFromMarketingEmails":{"verb":"GET","url":"/api/v1/unsubscribe-from-marketing-emails","args":["emailAddress"]},"getStripeCheckoutSessionUrl":{"verb":"POST","url":"/api/v1/customers/get-stripe-checkout-session-url","args":["quoteId"]},"getLlmGeneratedSql":{"verb":"POST","url":"/api/v1/admin/get-llm-generated-sql","args":["naturalLanguageQuestion"]}} + methods: {"redirectToStripeBillingPortal":{"verb":"GET","url":"/customers/update-subscription","args":[]},"downloadSitemap":{"verb":"GET","url":"/sitemap.xml","args":[]},"downloadRssFeed":{"verb":"GET","url":"/rss/:categoryName","args":["categoryName"]},"receiveUsageAnalytics":{"verb":"POST","url":"/api/v1/webhooks/receive-usage-analytics","args":["anonymousIdentifier","fleetVersion","licenseTier","numHostsEnrolled","numUsers","numTeams","numPolicies","numLabels","softwareInventoryEnabled","vulnDetectionEnabled","systemUsersEnabled","hostsStatusWebHookEnabled","numWeeklyActiveUsers","numWeeklyPolicyViolationDaysActual","numWeeklyPolicyViolationDaysPossible","hostsEnrolledByOperatingSystem","hostsEnrolledByOrbitVersion","hostsEnrolledByOsqueryVersion","storedErrors","numHostsNotResponding","organization","mdmMacOsEnabled","mdmWindowsEnabled","liveQueryDisabled","hostExpiryEnabled","numSoftwareVersions","numHostSoftwares","numSoftwareTitles","numHostSoftwareInstalledPaths","numSoftwareCPEs","numSoftwareCVEs","aiFeaturesDisabled","maintenanceWindowsEnabled","maintenanceWindowsConfigured","numHostsFleetDesktopEnabled","numQueries"]},"receiveFromGithub":{"verb":"GET","url":"/api/v1/webhooks/github","args":["botSignature","action","sender","repository","changes","issue","comment","pull_request","label","release"]},"receiveFromStripe":{"verb":"POST","url":"/api/v1/webhooks/receive-from-stripe","args":["id","type","data","webhookSecret"]},"getEstDeviceCertificate":{"verb":"POST","url":"/api/v1/get-est-device-certificate","args":["csrData","authToken"]},"deliverContactFormMessage":{"verb":"POST","url":"/api/v1/deliver-contact-form-message","args":["emailAddress","firstName","lastName","message"]},"sendPasswordRecoveryEmail":{"verb":"POST","url":"/api/v1/entrance/send-password-recovery-email","args":["emailAddress"]},"signup":{"verb":"POST","url":"/api/v1/customers/signup","args":["emailAddress","password","organization","firstName","lastName","signupReason"]},"updateProfile":{"verb":"POST","url":"/api/v1/account/update-profile","args":["firstName","lastName","organization","emailAddress"]},"updatePassword":{"verb":"POST","url":"/api/v1/account/update-password","args":["oldPassword","newPassword"]},"updateBillingCard":{"verb":"POST","url":"/api/v1/account/update-billing-card","args":["stripeToken","billingCardLast4","billingCardBrand","billingCardExpMonth","billingCardExpYear"]},"login":{"verb":"POST","url":"/api/v1/customers/login","args":["emailAddress","password","rememberMe"]},"logout":{"verb":"GET","url":"/api/v1/account/logout","args":[]},"createQuote":{"verb":"POST","url":"/api/v1/customers/create-quote","args":["numberOfHosts"]},"saveBillingInfoAndSubscribe":{"verb":"POST","url":"/api/v1/customers/save-billing-info-and-subscribe","args":["quoteId","organization","firstName","lastName","paymentSource"]},"updatePasswordAndLogin":{"verb":"POST","url":"/api/v1/entrance/update-password-and-login","args":["password","token"]},"deliverDemoSignup":{"verb":"POST","url":"/api/v1/deliver-demo-signup","args":["emailAddress"]},"createOrUpdateOneNewsletterSubscription":{"verb":"POST","url":"/api/v1/create-or-update-one-newsletter-subscription","args":["emailAddress"]},"unsubscribeFromAllNewsletters":{"verb":"GET","url":"/api/v1/unsubscribe-from-all-newsletters","args":["emailAddress"]},"buildLicenseKey":{"verb":"POST","url":"/api/v1/admin/build-license-key","args":["numberOfHosts","organization","expiresAt","partnerName"]},"createVantaAuthorizationRequest":{"verb":"POST","url":"/api/v1/create-vanta-authorization-request","args":["emailAddress","fleetInstanceUrl","fleetApiKey","redirectToExternalPageAfterAuthorization","sharedSecret"]},"redirectVantaAuthorizationRequest":{"verb":"GET","url":"/redirect-vanta-authorization-request","args":["vantaSourceId","state","vantaAuthorizationRequestURL","redirectAfterSetup"]},"deliverMdmBetaSignup":{"verb":"POST","url":"/api/v1/deliver-mdm-beta-signup","args":["emailAddress","fullName","jobTitle","numberOfHosts"]},"getHumanInterpretationFromOsquerySql":{"verb":"POST","url":"/api/v1/get-human-interpretation-from-osquery-sql","args":["sql"]},"deliverAppleCsr":{"verb":"POST","url":"/api/v1/deliver-apple-csr","args":["unsignedCsrData","deliveryMethod"]},"deliverMdmDemoEmail":{"verb":"POST","url":"/api/v1/deliver-mdm-demo-email","args":["emailAddress"]},"provisionSandboxInstanceAndDeliverEmail":{"verb":"POST","url":"/api/v1/admin/provision-sandbox-instance-and-deliver-email","args":["userId"]},"deliverTalkToUsFormSubmission":{"verb":"POST","url":"/api/v1/deliver-talk-to-us-form-submission","args":["emailAddress","firstName","lastName","organization","numberOfHosts","primaryBuyingSituation"]},"saveQuestionnaireProgress":{"verb":"POST","url":"/api/v1/save-questionnaire-progress","args":["currentStep","formData"]},"updateStartCtaVisibility":{"verb":"POST","url":"/api/v1/account/update-start-cta-visibility","args":[]},"deliverDealRegistrationSubmission":{"verb":"POST","url":"/api/v1/deliver-deal-registration-submission","args":["submittersFirstName","submittersLastName","submittersEmailAddress","submittersOrganization","customersFirstName","customersLastName","customersEmailAddress","linkedinUrl","customersOrganization","customersCurrentMdm","otherMdmEvaluated","preferredHosting","expectedDealSize","expectedCloseDate","notes"]},"unsubscribeFromMarketingEmails":{"verb":"GET","url":"/api/v1/unsubscribe-from-marketing-emails","args":["emailAddress"]},"getStripeCheckoutSessionUrl":{"verb":"POST","url":"/api/v1/customers/get-stripe-checkout-session-url","args":["quoteId"]},"getLlmGeneratedSql":{"verb":"POST","url":"/api/v1/query-generator/get-llm-generated-sql","args":["naturalLanguageQuestion"]}} /* eslint-enable */ }); diff --git a/website/config/routes.js b/website/config/routes.js index 2e8ef0c80487..47b332efde01 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -448,7 +448,7 @@ module.exports.routes = { } }, - 'GET /admin/query-generator': { action: 'admin/view-query-generator' }, + 'GET /query-generator': { action: 'query-generator/view-query-generator' }, // ╦ ╔═╗╔═╗╔═╗╔═╗╦ ╦ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗ // ║ ║╣ ║ ╦╠═╣║ ╚╦╝ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗ @@ -907,5 +907,5 @@ module.exports.routes = { 'POST /api/v1/deliver-deal-registration-submission': { action: 'deliver-deal-registration-submission' }, '/api/v1/unsubscribe-from-marketing-emails': { action: 'unsubscribe-from-marketing-emails' }, 'POST /api/v1/customers/get-stripe-checkout-session-url': { action: 'customers/get-stripe-checkout-session-url' }, - 'POST /api/v1/admin/get-llm-generated-sql': { action: 'admin/get-llm-generated-sql' }, + 'POST /api/v1/query-generator/get-llm-generated-sql': { action: 'query-generator/get-llm-generated-sql' }, }; diff --git a/website/views/layouts/layout.ejs b/website/views/layouts/layout.ejs index de22654b3b4a..47f35ebc6371 100644 --- a/website/views/layouts/layout.ejs +++ b/website/views/layouts/layout.ejs @@ -206,6 +206,7 @@
+ Generate queries License generator HTML Email preview tool
@@ -289,7 +290,7 @@ Admin pages
- Generate queries + Generate queries License generator HTML Email preview tool
From 82b746efece30b0bce473f6ac617744b879cfb59 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 9 Jan 2025 14:10:36 -0600 Subject: [PATCH 2/3] Update user model, add new policy for query generator --- website/api/models/User.js | 6 +++ .../policies/has-query-generator-access.js | 37 +++++++++++++++++++ website/config/policies.js | 1 + 3 files changed, 44 insertions(+) create mode 100644 website/api/policies/has-query-generator-access.js diff --git a/website/api/models/User.js b/website/api/models/User.js index 7f325e3ffaf4..abad1efddf23 100644 --- a/website/api/models/User.js +++ b/website/api/models/User.js @@ -271,6 +271,12 @@ without necessarily having a billing card.` description: 'A JS timestamp of when this user\'s Fleet Premium trial license key expires.', }, + canUseQueryGenerator: { + type: 'boolean', + description: 'Whether or not this user can access the query generator page', + defaultsTo: false, + }, + // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ diff --git a/website/api/policies/has-query-generator-access.js b/website/api/policies/has-query-generator-access.js new file mode 100644 index 000000000000..5d169508f3aa --- /dev/null +++ b/website/api/policies/has-query-generator-access.js @@ -0,0 +1,37 @@ +/** + * has-query-generator-access + * + * A simple policy that blocks requests from users who have not been granted access to the query generator. + * + * For more about how to use policies, see: + * https://sailsjs.com/config/policies + * https://sailsjs.com/docs/concepts/policies + * https://sailsjs.com/docs/concepts/policies/access-control-and-permissions + */ +module.exports = async function (req, res, proceed) { + + // First, check whether the request comes from a logged-in user. + // > For more about where `req.me` comes from, check out this app's + // > custom hook (`api/hooks/custom/index.js`). + if (!req.me) { + // Rather than use the standard res.unauthorized(), if the request did not come from a logged-in user, + // we'll redirect them to an generic version of the customer login page. + if (req.wantsJSON) { + return res.sendStatus(401); + } else { + return res.redirect('/login'); + } + }//• + + // Check if this user can access the query generator. + if (!req.me.canUseQueryGenerator) { + return res.forbidden(); + // Then check that this user is a "super admin". + } else if (!req.me.isSuperAdmin) { + return res.forbidden(); + } + + // IWMIH, this user can access the query generator. + return proceed(); + +}; diff --git a/website/config/policies.js b/website/config/policies.js index 1da8cfff6397..ed7b3b0cba7f 100644 --- a/website/config/policies.js +++ b/website/config/policies.js @@ -12,6 +12,7 @@ module.exports.policies = { '*': 'is-logged-in', 'admin/*': 'is-super-admin', + 'query-generator/*': 'has-query-generator-access', // Bypass the `is-logged-in` policy for: 'entrance/*': true, From 7f1b3094466b2c0c337df07a7e829e568a4c3c4f Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 9 Jan 2025 14:18:43 -0600 Subject: [PATCH 3/3] update page locals and policy --- website/api/policies/has-query-generator-access.js | 2 +- website/config/routes.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/website/api/policies/has-query-generator-access.js b/website/api/policies/has-query-generator-access.js index 5d169508f3aa..572db7db1d4a 100644 --- a/website/api/policies/has-query-generator-access.js +++ b/website/api/policies/has-query-generator-access.js @@ -27,7 +27,7 @@ module.exports = async function (req, res, proceed) { if (!req.me.canUseQueryGenerator) { return res.forbidden(); // Then check that this user is a "super admin". - } else if (!req.me.isSuperAdmin) { + } else if (!req.me.canUseQueryGenerator && !req.me.isSuperAdmin) { return res.forbidden(); } diff --git a/website/config/routes.js b/website/config/routes.js index 47b332efde01..4ba4fd7df57b 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -448,7 +448,12 @@ module.exports.routes = { } }, - 'GET /query-generator': { action: 'query-generator/view-query-generator' }, + 'GET /query-generator': { + action: 'query-generator/view-query-generator', + locals: { + showAdminLinks: true, + } + }, // ╦ ╔═╗╔═╗╔═╗╔═╗╦ ╦ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗ // ║ ║╣ ║ ╦╠═╣║ ╚╦╝ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗