diff --git a/Node-1st-gen/bigquery-import/README.md b/Node-1st-gen/bigquery-import/README.md index 1a08e9ed4..0abb3c671 100644 --- a/Node-1st-gen/bigquery-import/README.md +++ b/Node-1st-gen/bigquery-import/README.md @@ -26,5 +26,9 @@ As an example we'll be using a simple logs database structure: Set the `bigquery.datasetName` and `bigquery.tableName` Google Cloud environment variables to match the Dataset name and the Table name where you want the logs written to. For this use: ```bash -firebase functions:config:set bigquery.datasetName="bar" bigquery.tableName="baz" +Add the following configuration to your `.env` file: +``` +BIGQUERY_DATASETNAME="bar" +BIGQUERY_TABLENAME="baz" +``` ``` diff --git a/Node-1st-gen/bigquery-import/functions/index.js b/Node-1st-gen/bigquery-import/functions/index.js index 9e99858ce..7406ca94a 100644 --- a/Node-1st-gen/bigquery-import/functions/index.js +++ b/Node-1st-gen/bigquery-import/functions/index.js @@ -16,18 +16,22 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {defineString} = require('firebase-functions/params'); const { BigQuery } = require('@google-cloud/bigquery'); const bigquery = new BigQuery(); +const bigqueryDatasetname = defineString('BIGQUERY_DATASETNAME'); +const bigqueryTablename = defineString('BIGQUERY_TABLENAME'); + /** * Writes all logs from the Realtime Database into bigquery. */ exports.addtobigquery = functions.database.ref('/logs/{logid}').onCreate((snapshot) => { - // TODO: Make sure you set the `bigquery.datasetName` Google Cloud environment variable. - const dataset = bigquery.dataset(functions.config().bigquery.datasetname); - // TODO: Make sure you set the `bigquery.tableName` Google Cloud environment variable. - const table = dataset.table(functions.config().bigquery.tablename); + // TODO: Make sure you set the `BIGQUERY_DATASETNAME` environment variable. + const dataset = bigquery.dataset(bigqueryDatasetname.value()); + // TODO: Make sure you set the `BIGQUERY_TABLENAME` environment variable. + const table = dataset.table(bigqueryTablename.value()); return table.insert({ ID: snapshot.key, diff --git a/Node-1st-gen/developer-motivator/README.md b/Node-1st-gen/developer-motivator/README.md index 51c5b1cf8..d7d4db38e 100644 --- a/Node-1st-gen/developer-motivator/README.md +++ b/Node-1st-gen/developer-motivator/README.md @@ -33,7 +33,7 @@ To deploy and test the sample: - Set the `dev_motivator.device_token` Google Cloud environment variables. For this use: ```bash - firebase functions:config:set dev_motivator.device_token="your_developer_device_token" + firebase functions:secrets:set DEV_MOTIVATOR_DEVICE_TOKEN ``` - Deploy your project's code using `firebase deploy` - You'll now get a notification on your mobile when a user opens your app for the first time and when they uninstall your app. diff --git a/Node-1st-gen/developer-motivator/functions/index.js b/Node-1st-gen/developer-motivator/functions/index.js index f5daa33e9..c79bd860c 100644 --- a/Node-1st-gen/developer-motivator/functions/index.js +++ b/Node-1st-gen/developer-motivator/functions/index.js @@ -17,17 +17,18 @@ const admin = require('firebase-admin'); const functions = require('firebase-functions/v1'); +const {defineSecret} = require('firebase-functions/params'); admin.initializeApp(); -// TODO: Make sure you configure the 'dev_motivator.device_token' Google Cloud environment variables. -const deviceToken = functions.config().dev_motivator.device_token; +// TODO: Make sure you configure the 'DEV_MOTIVATOR_DEVICE_TOKEN' secret. +const devMotivatorDeviceToken = defineSecret('DEV_MOTIVATOR_DEVICE_TOKEN'); /** * Triggers when the app is opened the first time in a user device and sends a notification to your developer device. * * The device model name, the city and the country of the user are sent in the notification message */ -exports.appinstalled = functions.analytics.event('first_open').onLog((event) => { +exports.appinstalled = functions.runWith({secrets: [devMotivatorDeviceToken]}).analytics.event('first_open').onLog((event) => { const user = event.user; const payload = { notification: { @@ -36,7 +37,7 @@ exports.appinstalled = functions.analytics.event('first_open').onLog((event) => } }; - return admin.messaging().send({token: deviceToken, notification: payload.notification}); + return admin.messaging().send({token: devMotivatorDeviceToken.value(), notification: payload.notification}); }); /** @@ -46,7 +47,7 @@ exports.appinstalled = functions.analytics.event('first_open').onLog((event) => * * The device model name, the city and the country of the user are sent in the notification message */ -exports.appremoved = functions.analytics.event('app_remove').onLog((event) => { +exports.appremoved = functions.runWith({secrets: [devMotivatorDeviceToken]}).analytics.event('app_remove').onLog((event) => { const user = event.user; const payload = { notification: { @@ -55,5 +56,5 @@ exports.appremoved = functions.analytics.event('app_remove').onLog((event) => { } }; - return admin.messaging().send({token: deviceToken, notification: payload.notification}); + return admin.messaging().send({token: devMotivatorDeviceToken.value(), notification: payload.notification}); }); diff --git a/Node-1st-gen/email-confirmation/README.md b/Node-1st-gen/email-confirmation/README.md index 26db34a27..8bc588561 100644 --- a/Node-1st-gen/email-confirmation/README.md +++ b/Node-1st-gen/email-confirmation/README.md @@ -45,7 +45,14 @@ The function triggers on changes to `/users/$uid` and exits if there are no chan 1. To be able to send emails with your Gmail account: enable access to [Less Secure Apps](https://www.google.com/settings/security/lesssecureapps) and [Display Unlock Captcha](https://accounts.google.com/DisplayUnlockCaptcha). For accounts with 2-step verification enabled [Generate an App Password](https://support.google.com/accounts/answer/185833). 1. Set the `gmail.email` and `gmail.password` Google Cloud environment variables to match the email and password of the Gmail account used to send emails (or the app password if your account has 2-step verification enabled). For this use: ```bash - firebase functions:config:set gmail.email="myusername@gmail.com" gmail.password="secretpassword" + Add the following configuration to your `.env` file: + ``` +GMAIL_EMAIL="myusername@gmail.com" +``` +Then, set the `GMAIL_PASSWORD` secret: +``` +firebase functions:secrets:set GMAIL_PASSWORD +``` ``` ## Deploy and test diff --git a/Node-1st-gen/email-confirmation/functions/index.js b/Node-1st-gen/email-confirmation/functions/index.js index bcab08520..fef1b7f07 100644 --- a/Node-1st-gen/email-confirmation/functions/index.js +++ b/Node-1st-gen/email-confirmation/functions/index.js @@ -16,22 +16,28 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString, defineSecret} = require('firebase-functions/params'); const nodemailer = require('nodemailer'); // Configure the email transport using the default SMTP transport and a GMail account. // For other types of transports such as Sendgrid see https://nodemailer.com/transports/ -// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables. -const gmailEmail = functions.config().gmail.email; -const gmailPassword = functions.config().gmail.password; -const mailTransport = nodemailer.createTransport({ - service: 'gmail', - auth: { - user: gmailEmail, - pass: gmailPassword, - }, +// TODO: Configure the `GMAIL_EMAIL` environment variable and the `GMAIL_PASSWORD` secret. +const gmailEmail = defineString('GMAIL_EMAIL'); +const gmailPassword = defineSecret('GMAIL_PASSWORD'); + +let mailTransport; +onInit(() => { + mailTransport = nodemailer.createTransport({ + service: 'gmail', + auth: { + user: gmailEmail.value(), + pass: gmailPassword.value(), + }, + }); }); // Sends an email confirmation when a user changes his mailing list subscription. -exports.sendEmailConfirmation = functions.database.ref('/users/{uid}').onWrite(async (change) => { +exports.sendEmailConfirmation = functions.runWith({secrets: [gmailPassword]}).database.ref('/users/{uid}').onWrite(async (change) => { // Early exit if the 'subscribedToMailingList' field has not changed if (change.after.child('subscribedToMailingList').val() === change.before.child('subscribedToMailingList').val()) { return null; diff --git a/Node-1st-gen/fulltext-search-firestore/functions/elastic.js b/Node-1st-gen/fulltext-search-firestore/functions/elastic.js index 1c48e47e5..f8eaf4f0a 100644 --- a/Node-1st-gen/fulltext-search-firestore/functions/elastic.js +++ b/Node-1st-gen/fulltext-search-firestore/functions/elastic.js @@ -14,6 +14,8 @@ * limitations under the License. */ const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString, defineSecret} = require('firebase-functions/params'); // [START init_elastic] const { Client } = require("@elastic/elasticsearch"); @@ -22,22 +24,25 @@ const { Client } = require("@elastic/elasticsearch"); // https://github.com/elastic/elasticsearch-js // // ID, username, and password are stored in functions config variables -const ELASTIC_ID = functions.config().elastic.id; -const ELASTIC_USERNAME = functions.config().elastic.username; -const ELASTIC_PASSWORD = functions.config().elastic.password; +const elasticId = defineString('ELASTIC_ID'); +const elasticUsername = defineString('ELASTIC_USERNAME'); +const elasticPassword = defineSecret('ELASTIC_PASSWORD'); -const client = new Client({ - cloud: { - id: ELASTIC_ID, - username: ELASTIC_USERNAME, - password: ELASTIC_PASSWORD, - } +let client; +onInit(() => { + client = new Client({ + cloud: { + id: elasticId.value(), + username: elasticUsername.value(), + password: elasticPassword.value(), + } + }); }); // [END init_elastic] // [START update_index_function_elastic] // Update the search index every time a blog post is written. -exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(async (snap, context) => { +exports.onNoteCreated = functions.runWith({secrets: [elasticPassword]}).firestore.document('notes/{noteId}').onCreate(async (snap, context) => { // Get the note document const note = snap.data(); @@ -54,7 +59,7 @@ exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate( // [END update_index_function_elastic] // [START search_function_elastic] -exports.searchNotes = functions.https.onCall(async (data, context) => { +exports.searchNotes = functions.runWith({secrets: [elasticPassword]}).https.onCall(async (data, context) => { const query = data.query; // Search for any notes where the text field contains the query text. diff --git a/Node-1st-gen/fulltext-search-firestore/functions/index.js b/Node-1st-gen/fulltext-search-firestore/functions/index.js index 083ef42d1..4aeddfa45 100644 --- a/Node-1st-gen/fulltext-search-firestore/functions/index.js +++ b/Node-1st-gen/fulltext-search-firestore/functions/index.js @@ -14,6 +14,8 @@ * limitations under the License. */ const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const algoliasearch = require('algoliasearch').default; // [START init_algolia] @@ -21,17 +23,21 @@ const algoliasearch = require('algoliasearch').default; // https://www.algolia.com/doc/api-client/javascript/getting-started/#install // // App ID and API Key are stored in functions config variables -const ALGOLIA_ID = functions.config().algolia.app_id; -const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key; -const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key; +const algoliaId = defineSecret('ALGOLIA_ID'); +const algoliaAdminKey = defineSecret('ALGOLIA_ADMIN_KEY'); +const algoliaSearchKey = defineSecret('ALGOLIA_SEARCH_KEY'); const ALGOLIA_INDEX_NAME = 'notes'; -const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY); + +let client; +onInit(() => { + client = algoliasearch(algoliaId.value(), algoliaAdminKey.value()); +}); // [END init_algolia] // [START update_index_function] // Update the search index every time a blog post is written. -exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate((snap, context) => { +exports.onNoteCreated = functions.runWith({secrets: [algoliaId, algoliaAdminKey]}).firestore.document('notes/{noteId}').onCreate((snap, context) => { // Get the note document const note = snap.data(); @@ -108,7 +114,7 @@ app.get('/', (req, res) => { }; // Call the Algolia API to generate a unique key based on our search key - const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params); + const key = client.generateSecuredApiKey(algoliaSearchKey.value(), params); // Then return this key as {key: '...key'} res.json({key}); @@ -116,5 +122,5 @@ app.get('/', (req, res) => { // Finally, pass our ExpressJS app to Cloud Functions as a function // called 'getSearchKey'; -exports.getSearchKey = functions.https.onRequest(app); +exports.getSearchKey = functions.runWith({secrets: [algoliaId, algoliaAdminKey, algoliaSearchKey]}).https.onRequest(app); // [END get_algolia_user_token] diff --git a/Node-1st-gen/fulltext-search-firestore/functions/typesense.js b/Node-1st-gen/fulltext-search-firestore/functions/typesense.js index ca63efdaf..c66ec5169 100644 --- a/Node-1st-gen/fulltext-search-firestore/functions/typesense.js +++ b/Node-1st-gen/fulltext-search-firestore/functions/typesense.js @@ -14,6 +14,8 @@ * limitations under the License. */ const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); // [START init_typesense] // Initialize Typesense, requires installing Typesense dependencies: @@ -21,43 +23,26 @@ const functions = require('firebase-functions/v1'); const Typesense = require("typesense"); // Typesense API keys are stored in functions config variables -const TYPESENSE_ADMIN_API_KEY = functions.config().typesense.admin_api_key; -const TYPESENSE_SEARCH_API_KEY = functions.config().typesense.search_api_key; +const typesenseAdminApiKey = defineSecret('TYPESENSE_ADMIN_API_KEY'); +const typesenseSearchApiKey = defineSecret('TYPESENSE_SEARCH_API_KEY'); -const client = new Typesense.Client({ - 'nodes': [{ - 'host': 'xxx.a1.typesense.net', // where xxx is the ClusterID of your Typesense Cloud cluster - 'port': '443', - 'protocol': 'https' - }], - 'apiKey': TYPESENSE_ADMIN_API_KEY, - 'connectionTimeoutSeconds': 2 +let client; +onInit(() => { + client = new Typesense.Client({ + 'nodes': [{ + 'host': 'xxx.a1.typesense.net', // where xxx is the ClusterID of your Typesense Cloud cluster + 'port': '443', + 'protocol': 'https' + }], + 'apiKey': typesenseAdminApiKey.value(), + 'connectionTimeoutSeconds': 2 + }); }); // [END init_typesense] -// [START create_typesense_collections] -async function createTypesenseCollections() { - // Every 'collection' in Typesense needs a schema. A collection only - // needs to be created one time before you index your first document. - // - // Alternatively, use auto schema detection: - // https://typesense.org/docs/latest/api/collections.html#with-auto-schema-detection - const notesCollection = { - 'name': 'notes', - 'fields': [ - {'name': 'id', 'type': 'string'}, - {'name': 'owner', 'type': 'string' }, - {'name': 'text', 'type': 'string' } - ] - }; - - await client.collections().create(notesCollection); -} -// [END create_typesense_collections] - // [START update_index_function_typesense] // Update the search index every time a blog post is written. -exports.onNoteWritten = functions.firestore.document('notes/{noteId}').onWrite(async (snap, context) => { +exports.onNoteWritten = functions.runWith({secrets: [typesenseAdminApiKey]}).firestore.document('notes/{noteId}').onWrite(async (snap, context) => { // Use the 'nodeId' path segment as the identifier for Typesense const id = context.params.noteId; @@ -78,7 +63,7 @@ exports.onNoteWritten = functions.firestore.document('notes/{noteId}').onWrite(a // [END update_index_function_typesense] // [START api_key_function_typesense] -exports.getScopedApiKey = functions.https.onCall(async (data, context) => { +exports.getScopedApiKey = functions.runWith({secrets: [typesenseAdminApiKey, typesenseSearchApiKey]}).https.onCall(async (data, context) => { // Ensure that the user is authenticated with Firebase Auth if (!(context.auth && context.auth.uid)) { throw new functions.https.HttpsError('permission-denied', 'Must be signed in!'); @@ -87,7 +72,7 @@ exports.getScopedApiKey = functions.https.onCall(async (data, context) => { // Generate a scoped API key which allows the user to search ONLY // documents which belong to them (based on the 'owner' field). const scopedApiKey = client.keys().generateScopedSearchKey( - TYPESENSE_SEARCH_API_KEY, + typesenseSearchApiKey.value(), { 'filter_by': `owner:${context.auth.uid}` } diff --git a/Node-1st-gen/fulltext-search/README.md b/Node-1st-gen/fulltext-search/README.md index a2327355f..355252560 100644 --- a/Node-1st-gen/fulltext-search/README.md +++ b/Node-1st-gen/fulltext-search/README.md @@ -50,5 +50,6 @@ Enable Billing on your Firebase project by switching to the Blaze plan. You need Set the `algolia.app_id` and `algolia.api_key` Google Cloud environment variables to match the Algolia application ID and API key of your account. For this use: ```bash -firebase functions:config:set algolia.app_id="myAlgoliaAppId" algolia.api_key="myAlgoliaApiKey" +firebase functions:secrets:set ALGOLIA_APP_ID +firebase functions:secrets:set ALGOLIA_API_KEY ``` diff --git a/Node-1st-gen/fulltext-search/functions/index.js b/Node-1st-gen/fulltext-search/functions/index.js index f0d234192..eb2e9fa06 100644 --- a/Node-1st-gen/fulltext-search/functions/index.js +++ b/Node-1st-gen/fulltext-search/functions/index.js @@ -16,19 +16,27 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const admin = require('firebase-admin'); admin.initializeApp(); // Authenticate to Algolia Database. -// TODO: Make sure you configure the `algolia.app_id` and `algolia.api_key` Google Cloud environment variables. +// TODO: Make sure you configure the `ALGOLIA_APP_ID` and `ALGOLIA_API_KEY` secrets. const algoliasearch = require('algoliasearch').default; -const client = algoliasearch(functions.config().algolia.app_id, functions.config().algolia.api_key); +const algoliaAppId = defineSecret('ALGOLIA_APP_ID'); +const algoliaApiKey = defineSecret('ALGOLIA_API_KEY'); + +let client; +onInit(() => { + client = algoliasearch(algoliaAppId.value(), algoliaApiKey.value()); +}); // Name fo the algolia index for Blog posts content. const ALGOLIA_POSTS_INDEX_NAME = 'blogposts'; // Updates the search index when new blog entries are created or updated. -exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite( +exports.indexentry = functions.runWith({secrets: [algoliaAppId, algoliaApiKey]}).database.ref('/blog-posts/{blogid}/text').onWrite( async (data, context) => { const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME); const firebaseObject = { @@ -42,7 +50,7 @@ exports.indexentry = functions.database.ref('/blog-posts/{blogid}/text').onWrite // Starts a search query whenever a query is requested (by adding one to the `/search/queries` // element. Search results are then written under `/search/results`. -exports.searchentry = functions.database.ref('/search/queries/{queryid}').onCreate( +exports.searchentry = functions.runWith({secrets: [algoliaAppId, algoliaApiKey]}).database.ref('/search/queries/{queryid}').onCreate( async (snap, context) => { const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME); diff --git a/Node-1st-gen/github-to-slack/README.md b/Node-1st-gen/github-to-slack/README.md index 830d962f4..b1fd16172 100644 --- a/Node-1st-gen/github-to-slack/README.md +++ b/Node-1st-gen/github-to-slack/README.md @@ -30,7 +30,8 @@ To test this integration: - [Add an **Incoming Webhook**](https://my.slack.com/services/new/incoming-webhook/) to your Slack channel and take note of the **Webhook URL**. - Set the `slack.webhook_url` and `github.secret` Google Cloud environment variables to match the email and password of the Gmail account used to send emails. For this use: ```bash - firebase functions:config:set slack.webhook_url="https://hooks.slack.com/services/..." github.secret="A_SECRET_YOU_DEFINED_WHEN_SETTING_UP_THE_GITHUB_WEBHOOK" + firebase functions:secrets:set SLACK_WEBHOOK_URL + firebase functions:secrets:set GITHUB_SECRET ``` - Deploy your project using `firebase deploy` - Push a commit to your GitHub repo diff --git a/Node-1st-gen/github-to-slack/functions/index.js b/Node-1st-gen/github-to-slack/functions/index.js index 64624a6ed..dcc4010c7 100644 --- a/Node-1st-gen/github-to-slack/functions/index.js +++ b/Node-1st-gen/github-to-slack/functions/index.js @@ -16,19 +16,23 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {defineSecret} = require('firebase-functions/params'); const crypto = require('node:crypto'); const secureCompare = require('secure-compare'); +const githubSecret = defineSecret('GITHUB_SECRET'); +const slackWebhookUrl = defineSecret('SLACK_WEBHOOK_URL'); + /** * Webhook that will be called each time there is a new GitHub commit and will post a message to * Slack. */ -exports.githubWebhook = functions.https.onRequest(async (req, res) => { +exports.githubWebhook = functions.runWith({secrets: [githubSecret, slackWebhookUrl]}).https.onRequest(async (req, res) => { const cipher = 'sha1'; const signature = req.headers['x-hub-signature']; - // TODO: Configure the `github.secret` Google Cloud environment variables. - const hmac = crypto.createHmac(cipher, functions.config().github.secret) + // TODO: Configure the `GITHUB_SECRET` secret. + const hmac = crypto.createHmac(cipher, githubSecret.value()) .update(req.rawBody) .digest('hex'); const expectedSignature = `${cipher}=${hmac}`; @@ -58,7 +62,7 @@ exports.githubWebhook = functions.https.onRequest(async (req, res) => { * Post a message to Slack about the new GitHub commit. */ async function postToSlack(url, commits, repo) { - const response = await fetch(functions.config().slack.webhook_url, { + const response = await fetch(slackWebhookUrl.value(), { method: "POST", body: JSON.stringify({ text: `<${url}|${commits} new commit${ diff --git a/Node-1st-gen/google-sheet-sync/README.md b/Node-1st-gen/google-sheet-sync/README.md index ed2f52509..8b1ebfdf7 100644 --- a/Node-1st-gen/google-sheet-sync/README.md +++ b/Node-1st-gen/google-sheet-sync/README.md @@ -33,16 +33,17 @@ To deploy and test the sample: 1. Using the Google APIs Console [create an OAuth Client ID](https://console.cloud.google.com/apis/credentials/oauthclient?project=_) Click this link, select your project and then choose **Web Application**. In **Authorized redirect URIs**, you’ll need to enter `https://{YOUR-PROJECT-ID}.firebaseapp.com/oauthcallback`. 1. Configure your Google API client ID and secret by running: ```bash - firebase functions:config:set googleapi.client_id="YOUR_CLIENT_ID" googleapi.client_secret="YOUR_CLIENT_SECRET" + firebase functions:secrets:set GOOGLEAPI_CLIENT_ID + firebase functions:secrets:set GOOGLEAPI_CLIENT_SECRET ``` 1. Create a new Google Sheet, and copy the long string in the middle of the Sheet URL. This is the Spreadsheet ID. 1. Configure your Google Spreadsheet ID by running: ```bash - firebase functions:config:set googleapi.sheet_id="YOUR_SPREADSHEET_ID" + Add the following configuration to your `.env` file: ``` - 1. Specify the path of the data in the Realtime Database that you want automatically copied to your Spreadsheet: - ```bash - firebase functions:config:set watchedpaths.data_path="THE_DATA_PATH_YOU_WANT" +GOOGLEAPI_SHEET_ID="YOUR_SPREADSHEET_ID" +WATCHEDPATHS_DATA_PATH="THE_DATA_PATH_YOU_WANT" +``` ``` 1. Deploy your project using `firebase deploy` 1. Configure the app once by opening the following URL and going through the auth flow `https://{YOUR-PROJET-ID}.firebaseapp.com/authgoogleapi` diff --git a/Node-1st-gen/google-sheet-sync/functions/index.js b/Node-1st-gen/google-sheet-sync/functions/index.js index 12aa3fa9e..ccc3015ac 100644 --- a/Node-1st-gen/google-sheet-sync/functions/index.js +++ b/Node-1st-gen/google-sheet-sync/functions/index.js @@ -18,36 +18,39 @@ // Sample trigger function that copies new Firebase data to a Google Sheet const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString, defineSecret} = require('firebase-functions/params'); const admin = require('firebase-admin'); admin.initializeApp(); const {OAuth2Client} = require('google-auth-library'); const {google} = require('googleapis'); -// TODO: Use firebase functions:config:set to configure your googleapi object: -// googleapi.client_id = Google API client ID, -// googleapi.client_secret = client secret, and -// googleapi.sheet_id = Google Sheet id (long string in middle of sheet URL) -const CONFIG_CLIENT_ID = functions.config().googleapi.client_id; -const CONFIG_CLIENT_SECRET = functions.config().googleapi.client_secret; -const CONFIG_SHEET_ID = functions.config().googleapi.sheet_id; +// TODO: Configure the `GOOGLEAPI_CLIENT_ID` and `GOOGLEAPI_CLIENT_SECRET` secrets, +// and the `GOOGLEAPI_SHEET_ID` environment variable. +const googleApiClientId = defineSecret('GOOGLEAPI_CLIENT_ID'); +const googleApiClientSecret = defineSecret('GOOGLEAPI_CLIENT_SECRET'); +const googleApiSheetId = defineString('GOOGLEAPI_SHEET_ID'); -// TODO: Use firebase functions:config:set to configure your watchedpaths object: -// watchedpaths.data_path = Firebase path for data to be synced to Google Sheet -const CONFIG_DATA_PATH = functions.config().watchedpaths.data_path; +// TODO: Configure the `WATCHEDPATHS_DATA_PATH` environment variable. +const watchedpathsDataPath = defineString('WATCHEDPATHS_DATA_PATH'); // The OAuth Callback Redirect. const FUNCTIONS_REDIRECT = `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/oauthcallback`; // setup for authGoogleAPI const SCOPES = ['https://www.googleapis.com/auth/spreadsheets']; -const functionsOauthClient = new OAuth2Client(CONFIG_CLIENT_ID, CONFIG_CLIENT_SECRET, - FUNCTIONS_REDIRECT); + +let functionsOauthClient; +onInit(() => { + functionsOauthClient = new OAuth2Client(googleApiClientId.value(), googleApiClientSecret.value(), + FUNCTIONS_REDIRECT); +}); // OAuth token cached locally. let oauthTokens = null; // visit the URL for this Function to request tokens -exports.authgoogleapi = functions.https.onRequest((req, res) => { +exports.authgoogleapi = functions.runWith({secrets: [googleApiClientId, googleApiClientSecret]}).https.onRequest((req, res) => { res.set('Cache-Control', 'private, max-age=0, s-maxage=0'); res.redirect(functionsOauthClient.generateAuthUrl({ access_type: 'offline', @@ -61,7 +64,7 @@ const DB_TOKEN_PATH = '/api_tokens'; // after you grant access, you will be redirected to the URL for this Function // this Function stores the tokens to your Firebase database -exports.oauthcallback = functions.https.onRequest(async (req, res) => { +exports.oauthcallback = functions.runWith({secrets: [googleApiClientId, googleApiClientSecret]}).https.onRequest(async (req, res) => { res.set('Cache-Control', 'private, max-age=0, s-maxage=0'); const code = `${req.query.code}`; try { @@ -75,12 +78,15 @@ exports.oauthcallback = functions.https.onRequest(async (req, res) => { } }); -// trigger function to write to Sheet when new data comes in on CONFIG_DATA_PATH -exports.appendrecordtospreadsheet = functions.database.ref(`${CONFIG_DATA_PATH}/{ITEM}`).onCreate( - (snap) => { +// trigger function to write to Sheet when new data comes in on watchedpathsDataPath +exports.appendrecordtospreadsheet = functions.runWith({secrets: [googleApiClientId, googleApiClientSecret]}).database.ref('/{path}/{ITEM}').onCreate( + (snap, context) => { + if (context.params.path !== watchedpathsDataPath.value()) { + return null; + } const newRecord = snap.val(); return appendPromise({ - spreadsheetId: CONFIG_SHEET_ID, + spreadsheetId: googleApiSheetId.value(), range: 'A:C', valueInputOption: 'USER_ENTERED', insertDataOption: 'INSERT_ROWS', @@ -111,6 +117,7 @@ function appendPromise(requestWithoutAuth) { // checks if oauthTokens have been loaded into memory, and if not, retrieves them async function getAuthorizedClient() { if (oauthTokens) { + functionsOauthClient.setCredentials(oauthTokens); return functionsOauthClient; } const snapshot = await admin.database().ref(DB_TOKEN_PATH).once('value'); @@ -119,13 +126,13 @@ async function getAuthorizedClient() { return functionsOauthClient; } -// HTTPS function to write new data to CONFIG_DATA_PATH, for testing +// HTTPS function to write new data to watchedpathsDataPath, for testing exports.testsheetwrite = functions.https.onRequest(async (req, res) => { const random1 = Math.floor(Math.random() * 100); const random2 = Math.floor(Math.random() * 100); const random3 = Math.floor(Math.random() * 100); const ID = new Date().getUTCMilliseconds(); - await admin.database().ref(`${CONFIG_DATA_PATH}/${ID}`).set({ + await admin.database().ref(`${watchedpathsDataPath.value()}/${ID}`).set({ firstColumn: random1, secondColumn: random2, thirdColumn: random3, diff --git a/Node-1st-gen/instagram-auth/README.md b/Node-1st-gen/instagram-auth/README.md index 0306d4d9f..75950ec35 100644 --- a/Node-1st-gen/instagram-auth/README.md +++ b/Node-1st-gen/instagram-auth/README.md @@ -19,7 +19,8 @@ Create and setup your Instagram app: 1. Copy the **Client ID** and **Client Secret** of your Instagram app and use them to set the `instagram.client_id` and `instagram.client_secret` Google Cloud environment variables. For this use: ```bash - firebase functions:config:set instagram.client_id="yourClientID" instagram.client_secret="yourClientSecret" + firebase functions:secrets:set INSTAGRAM_CLIENT_ID + firebase functions:secrets:set INSTAGRAM_CLIENT_SECRET ``` > Make sure the Instagram Client Secret is always kept secret. For instance do not save it in your version control system. diff --git a/Node-1st-gen/instagram-auth/functions/index.js b/Node-1st-gen/instagram-auth/functions/index.js index fa6d31103..e8cbdaba6 100644 --- a/Node-1st-gen/instagram-auth/functions/index.js +++ b/Node-1st-gen/instagram-auth/functions/index.js @@ -16,6 +16,8 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const cookieParser = require('cookie-parser'); const crypto = require('node:crypto'); @@ -31,32 +33,31 @@ admin.initializeApp({ const OAUTH_REDIRECT_URI = `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`; const OAUTH_SCOPES = 'basic'; -/** - * Creates a configured simple-oauth2 client for Instagram. - */ -function instagramOAuth2Client() { +const instagramClientId = defineSecret('INSTAGRAM_CLIENT_ID'); +const instagramClientSecret = defineSecret('INSTAGRAM_CLIENT_SECRET'); + +let oauth2; +onInit(() => { // Instagram OAuth 2 setup - // TODO: Configure the `instagram.client_id` and `instagram.client_secret` Google Cloud environment variables. + // TODO: Configure the `INSTAGRAM_CLIENT_ID` and `INSTAGRAM_CLIENT_SECRET` secrets. const credentials = { client: { - id: functions.config().instagram.client_id, - secret: functions.config().instagram.client_secret, + id: instagramClientId.value(), + secret: instagramClientSecret.value(), }, auth: { tokenHost: 'https://api.instagram.com', tokenPath: '/oauth/access_token', }, }; - return require('simple-oauth2').create(credentials); -} + oauth2 = require('simple-oauth2').create(credentials); +}); /** * Redirects the User to the Instagram authentication consent screen. Also the 'state' cookie is set for later state * verification. */ -exports.redirect = functions.https.onRequest((req, res) => { - const oauth2 = instagramOAuth2Client(); - +exports.redirect = functions.runWith({secrets: [instagramClientId, instagramClientSecret]}).https.onRequest((req, res) => { cookieParser()(req, res, () => { const state = req.cookies.state || crypto.randomBytes(20).toString('hex'); functions.logger.log('Setting verification state:', state); @@ -81,9 +82,7 @@ exports.redirect = functions.https.onRequest((req, res) => { * The Firebase custom auth token, display name, photo URL and Instagram acces token are sent back in a JSONP callback * function with function name defined by the 'callback' query parameter. */ -exports.token = functions.https.onRequest(async (req, res) => { - const oauth2 = instagramOAuth2Client(); - +exports.token = functions.runWith({secrets: [instagramClientId, instagramClientSecret]}).https.onRequest(async (req, res) => { try { return cookieParser()(req, res, async () => { functions.logger.log('Received verification state:', req.cookies.state); diff --git a/Node-1st-gen/linkedin-auth/README.md b/Node-1st-gen/linkedin-auth/README.md index 91718f758..f76f2caca 100644 --- a/Node-1st-gen/linkedin-auth/README.md +++ b/Node-1st-gen/linkedin-auth/README.md @@ -20,7 +20,8 @@ Create and setup your LinkedIn app: 1. Copy the **Client ID** and **Client Secret** of your LinkedIn app and use them to set the `linkedin.client_id` and `linkedin.client_secret` Google Cloud environment variables. For this use: ```bash - firebase functions:config:set linkedin.client_id="yourClientID" linkedin.client_secret="yourClientSecret" + firebase functions:secrets:set LINKEDIN_CLIENT_ID + firebase functions:secrets:set LINKEDIN_CLIENT_SECRET ``` > Make sure the LinkedIn Client Secret is always kept secret. For instance do not save this in your version control system. diff --git a/Node-1st-gen/linkedin-auth/functions/index.js b/Node-1st-gen/linkedin-auth/functions/index.js index 3109030ab..aba497e85 100644 --- a/Node-1st-gen/linkedin-auth/functions/index.js +++ b/Node-1st-gen/linkedin-auth/functions/index.js @@ -16,6 +16,8 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const cookieParser = require('cookie-parser'); const crypto = require('crypto'); @@ -30,25 +32,22 @@ admin.initializeApp({ const OAUTH_SCOPES = ['r_basicprofile', 'r_emailaddress']; -/** - * Creates a configured LinkedIn API Client instance. - */ -function linkedInClient() { - // LinkedIn OAuth 2 setup - // TODO: Configure the `linkedin.client_id` and `linkedin.client_secret` Google Cloud environment variables. - return require('node-linkedin')( - functions.config().linkedin.client_id, - functions.config().linkedin.client_secret, - `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`); -} +const linkedinClientId = defineSecret('LINKEDIN_CLIENT_ID'); +const linkedinClientSecret = defineSecret('LINKEDIN_CLIENT_SECRET'); + +let Linkedin; +onInit(() => { + Linkedin = require('node-linkedin')( + linkedinClientId.value(), + linkedinClientSecret.value(), + `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`); +}); /** * Redirects the User to the LinkedIn authentication consent screen. ALso the 'state' cookie is set for later state * verification. */ -exports.redirect = functions.https.onRequest((req, res) => { - const Linkedin = linkedInClient(); - +exports.redirect = functions.runWith({secrets: [linkedinClientId, linkedinClientSecret]}).https.onRequest((req, res) => { cookieParser()(req, res, () => { const state = req.cookies.state || crypto.randomBytes(20).toString('hex'); functions.logger.log('Setting verification state:', state); @@ -67,9 +66,7 @@ exports.redirect = functions.https.onRequest((req, res) => { * The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the * 'callback' query parameter. */ -exports.token = functions.https.onRequest((req, res) => { - const Linkedin = linkedInClient(); - +exports.token = functions.runWith({secrets: [linkedinClientId, linkedinClientSecret]}).https.onRequest((req, res) => { try { return cookieParser()(req, res, () => { if (!req.cookies.state) { diff --git a/Node-1st-gen/okta-auth/functions/index.js b/Node-1st-gen/okta-auth/functions/index.js index 5e9a61750..1a1d9e661 100644 --- a/Node-1st-gen/okta-auth/functions/index.js +++ b/Node-1st-gen/okta-auth/functions/index.js @@ -32,20 +32,24 @@ if (envCfg.parsed && envCfg.parsed.GOOGLE_APPLICATION_CREDENTIALS) { } const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString} = require('firebase-functions/params'); const firebaseAdmin = require('firebase-admin'); const firebaseApp = firebaseAdmin.initializeApp(); -const OKTA_ORG_URL = functions.config().okta_auth.org_url +const oktaOrgUrl = defineString('OKTA_ORG_URL'); const OktaJwtVerifier = require('@okta/jwt-verifier'); -const oktaJwtVerifier = new OktaJwtVerifier({ - issuer: `${OKTA_ORG_URL}/oauth2/default` + +let oktaJwtVerifier; +onInit(() => { + oktaJwtVerifier = new OktaJwtVerifier({ + issuer: `${oktaOrgUrl.value()}/oauth2/default` + }); }); // Update CORS_ORIGIN to the base URL of your web client before deploying or // using a non-standard emulator configuration. -const CORS_ORIGIN = functions.config().okta_auth.cors_origin || - 'http://localhost:5000'; -const cors = require('cors')({ origin: CORS_ORIGIN }); +const corsOrigin = defineString('CORS_ORIGIN'); // Middleware to authenticate requests with an Okta access token. // https://developer.okta.com/docs/guides/protect-your-api/nodeexpress/require-authentication/ @@ -72,6 +76,11 @@ const oktaAuth = async (req, res, next) => { } // Get a Firebase custom auth token for the authenticated Okta user. +let cors; +onInit(() => { + cors = require('cors')({ origin: corsOrigin.value() }); +}); + app.get('/firebaseCustomToken', [cors, oktaAuth], async (req, res) => { const oktaUid = req.jwt.claims.uid; try { diff --git a/Node-1st-gen/paypal/README.md b/Node-1st-gen/paypal/README.md index 2140184ff..8f499f16e 100644 --- a/Node-1st-gen/paypal/README.md +++ b/Node-1st-gen/paypal/README.md @@ -30,11 +30,11 @@ The dependencies are listed in [functions/package.json](functions/package.json). 1. Setup [your Paypal API Client ID and Secret](https://developer.paypal.com/developer/applications/) in your Cloud Function. Run in the command line: ```sh - firebase functions:config:set paypal.client_id="yourPaypalClientID" + firebase functions:secrets:set PAYPAL_CLIENT_ID ``` ```sh - firebase functions:config:set paypal.client_secret="yourPaypalClientSecret" + firebase functions:secrets:set PAYPAL_CLIENT_SECRET ``` 1. Install dependencies locally by running: `cd functions; npm install; cd -` diff --git a/Node-1st-gen/paypal/functions/index.js b/Node-1st-gen/paypal/functions/index.js index be6c692db..087fb86fd 100644 --- a/Node-1st-gen/paypal/functions/index.js +++ b/Node-1st-gen/paypal/functions/index.js @@ -16,15 +16,22 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const paypal = require('paypal-rest-sdk'); // firebase-admin SDK init const admin = require('firebase-admin'); admin.initializeApp(); -// Configure your environment -paypal.configure({ - mode: 'sandbox', // sandbox or live - client_id: functions.config().paypal.client_id, // run: firebase functions:config:set paypal.client_id="yourPaypalClientID" - client_secret: functions.config().paypal.client_secret // run: firebase functions:config:set paypal.client_secret="yourPaypalClientSecret" + +const paypalClientId = defineSecret('PAYPAL_CLIENT_ID'); +const paypalClientSecret = defineSecret('PAYPAL_CLIENT_SECRET'); + +onInit(() => { + paypal.configure({ + mode: 'sandbox', // sandbox or live + client_id: paypalClientId.value(), + client_secret: paypalClientSecret.value(), + }); }); /** @@ -32,7 +39,7 @@ paypal.configure({ * Set up the payment information object * Initialize the payment and redirect the user to the PayPal payment page */ -exports.pay = functions.https.onRequest((req, res) => { +exports.pay = functions.runWith({secrets: [paypalClientId, paypalClientSecret]}).https.onRequest((req, res) => { // 1.Set up a payment information object, Build PayPal payment request const payReq = JSON.stringify({ intent: 'sale', @@ -86,7 +93,7 @@ exports.pay = functions.https.onRequest((req, res) => { }); // 3.Complete the payment. Use the payer and payment IDs provided in the query string following the redirect. -exports.process = functions.https.onRequest(async (req, res) => { +exports.process = functions.runWith({secrets: [paypalClientId, paypalClientSecret]}).https.onRequest(async (req, res) => { const paymentId = req.query.paymentId; const payerId = { payer_id: req.query.PayerID diff --git a/Node-1st-gen/quickstarts/email-users/functions/index.js b/Node-1st-gen/quickstarts/email-users/functions/index.js index ba617a844..26f33f5ad 100644 --- a/Node-1st-gen/quickstarts/email-users/functions/index.js +++ b/Node-1st-gen/quickstarts/email-users/functions/index.js @@ -16,6 +16,8 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString, defineSecret} = require('firebase-functions/params'); const nodemailer = require('nodemailer'); // Configure the email transport using the default SMTP transport and a GMail account. // For Gmail, enable these: @@ -23,14 +25,18 @@ const nodemailer = require('nodemailer'); // 2. https://accounts.google.com/DisplayUnlockCaptcha // For other types of transports such as Sendgrid see https://nodemailer.com/transports/ // TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables. -const gmailEmail = functions.config().gmail.email; -const gmailPassword = functions.config().gmail.password; -const mailTransport = nodemailer.createTransport({ - service: 'gmail', - auth: { - user: gmailEmail, - pass: gmailPassword, - }, +const gmailEmail = defineString('GMAIL_EMAIL'); +const gmailPassword = defineSecret('GMAIL_PASSWORD'); + +let mailTransport; +onInit(() => { + mailTransport = nodemailer.createTransport({ + service: 'gmail', + auth: { + user: gmailEmail.value(), + pass: gmailPassword.value(), + }, + }); }); // Your company name to include in the emails @@ -42,7 +48,7 @@ const APP_NAME = 'Cloud Storage for Firebase quickstart'; * Sends a welcome email to new user. */ // [START onCreateTrigger] -exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => { +exports.sendWelcomeEmail = functions.runWith({secrets: [gmailPassword]}).auth.user().onCreate((user) => { // [END onCreateTrigger] // [START eventAttributes] const email = user.email; // The email of the user. @@ -58,7 +64,7 @@ exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => { * Send an account deleted email confirmation to users who delete their accounts. */ // [START onDeleteTrigger] -exports.sendByeEmail = functions.auth.user().onDelete((user) => { +exports.sendByeEmail = functions.runWith({secrets: [gmailPassword]}).auth.user().onDelete((user) => { // [END onDeleteTrigger] const email = user.email; const displayName = user.displayName; diff --git a/Node-1st-gen/spotify-auth/README.md b/Node-1st-gen/spotify-auth/README.md index 425aab718..eb31c45a1 100644 --- a/Node-1st-gen/spotify-auth/README.md +++ b/Node-1st-gen/spotify-auth/README.md @@ -20,7 +20,8 @@ Create and setup your Spotify app: 1. Copy the **Client ID** and **Client Secret** of your Spotify app and use them to set the `spotify.client_id` and `spotify.client_secret` Google Cloud environment variables. For this use: ```bash - firebase functions:config:set spotify.client_id="yourClientID" spotify.client_secret="yourClientSecret" + firebase functions:secrets:set SPOTIFY_CLIENT_ID + firebase functions:secrets:set SPOTIFY_CLIENT_SECRET ``` > Make sure the Spotify Client Secret is always kept secret. For instance do not save this in your version control system. diff --git a/Node-1st-gen/spotify-auth/functions/index.js b/Node-1st-gen/spotify-auth/functions/index.js index f59383907..5275c4f99 100644 --- a/Node-1st-gen/spotify-auth/functions/index.js +++ b/Node-1st-gen/spotify-auth/functions/index.js @@ -16,6 +16,8 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const cookieParser = require('cookie-parser'); const crypto = require('node:crypto'); @@ -28,13 +30,20 @@ admin.initializeApp({ databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`, }); +const spotifyClientId = defineSecret('SPOTIFY_CLIENT_ID'); +const spotifyClientSecret = defineSecret('SPOTIFY_CLIENT_SECRET'); + // Spotify OAuth 2 setup -// TODO: Configure the `spotify.client_id` and `spotify.client_secret` Google Cloud environment variables. +// TODO: Configure the `spotifyClientId` and `spotifyClientSecret` secrets. const SpotifyWebApi = require('spotify-web-api-node'); -const Spotify = new SpotifyWebApi({ - clientId: functions.config().spotify.client_id, - clientSecret: functions.config().spotify.client_secret, - redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`, + +let Spotify; +onInit(() => { + Spotify = new SpotifyWebApi({ + clientId: spotifyClientId.value(), + clientSecret: spotifyClientSecret.value(), + redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`, + }); }); // Scopes to request. @@ -44,7 +53,7 @@ const OAUTH_SCOPES = ['user-read-email']; * Redirects the User to the Spotify authentication consent screen. Also the 'state' cookie is set for later state * verification. */ -exports.redirect = functions.https.onRequest((req, res) => { +exports.redirect = functions.runWith({secrets: [spotifyClientId, spotifyClientSecret]}).https.onRequest((req, res) => { cookieParser()(req, res, () => { const state = req.cookies.state || crypto.randomBytes(20).toString('hex'); functions.logger.log('Setting verification state:', state); @@ -60,7 +69,7 @@ exports.redirect = functions.https.onRequest((req, res) => { * The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the * 'callback' query parameter. */ -exports.token = functions.https.onRequest((req, res) => { +exports.token = functions.runWith({secrets: [spotifyClientId, spotifyClientSecret]}).https.onRequest((req, res) => { try { cookieParser()(req, res, () => { functions.logger.log('Received verification state:', req.cookies.state); diff --git a/Node-1st-gen/stripe/README.md b/Node-1st-gen/stripe/README.md index 6dcadc3cd..c01076451 100644 --- a/Node-1st-gen/stripe/README.md +++ b/Node-1st-gen/stripe/README.md @@ -32,7 +32,7 @@ This sample shows you how to create Stripe customers when your users sign up, se - Install dependencies locally by running: `cd functions; npm install; cd -` - [Add your Stripe API Secret Key](https://dashboard.stripe.com/account/apikeys) to firebase config: ```bash - firebase functions:config:set stripe.secret= + firebase functions:secrets:set STRIPE_SECRET ``` - Set your [Stripe publishable key](https://dashboard.stripe.com/account/apikeys) for the `STRIPE_PUBLISHABLE_KEY` const in [`/public/javascript/app.js`](./public/javascript/app.js#L16) - Deploy your project using `firebase deploy` @@ -54,7 +54,7 @@ Once you’re ready to go live, you will need to exchange your test keys for you - Update your Stripe secret config: ```bash - firebase functions:config:set stripe.secret= + firebase functions:secrets:set STRIPE_SECRET ``` - Set your [live publishable key](https://dashboard.stripe.com/account/apikeys) for the `STRIPE_PUBLISHABLE_KEY` const in [`/public/javascript/app.js`](./public/javascript/app.js#L16). - Redeploy both functions and hosting for the changes to take effect `firebase deploy`. diff --git a/Node-1st-gen/stripe/functions/index.js b/Node-1st-gen/stripe/functions/index.js index 66387eefa..f3eea5884 100644 --- a/Node-1st-gen/stripe/functions/index.js +++ b/Node-1st-gen/stripe/functions/index.js @@ -16,6 +16,8 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const admin = require('firebase-admin'); admin.initializeApp(); const { Logging } = require('@google-cloud/logging'); @@ -24,8 +26,13 @@ const logging = new Logging({ }); const { Stripe } = require('stripe'); -const stripe = new Stripe(functions.config().stripe.secret, { - apiVersion: '2020-08-27', +const stripeSecret = defineSecret('STRIPE_SECRET'); + +let stripe; +onInit(() => { + stripe = new Stripe(stripeSecret.value(), { + apiVersion: '2020-08-27', + }); }); /** @@ -33,7 +40,7 @@ const stripe = new Stripe(functions.config().stripe.secret, { * * @see https://stripe.com/docs/payments/save-and-reuse#web-create-customer */ -exports.createStripeCustomer = functions.auth.user().onCreate(async (user) => { +exports.createStripeCustomer = functions.runWith({secrets: [stripeSecret]}).auth.user().onCreate(async (user) => { const customer = await stripe.customers.create({ email: user.email }); const intent = await stripe.setupIntents.create({ customer: customer.id, @@ -49,7 +56,7 @@ exports.createStripeCustomer = functions.auth.user().onCreate(async (user) => { * When adding the payment method ID on the client, * this function is triggered to retrieve the payment method details. */ -exports.addPaymentMethodDetails = functions.firestore +exports.addPaymentMethodDetails = functions.runWith({secrets: [stripeSecret]}).firestore .document('/stripe_customers/{userId}/payment_methods/{pushId}') .onCreate(async (snap, context) => { try { @@ -84,7 +91,7 @@ exports.addPaymentMethodDetails = functions.firestore // [START chargecustomer] -exports.createStripePayment = functions.firestore +exports.createStripePayment = functions.runWith({secrets: [stripeSecret]}).firestore .document('stripe_customers/{userId}/payments/{pushId}') .onCreate(async (snap, context) => { const { amount, currency, payment_method } = snap.data(); @@ -125,7 +132,7 @@ exports.createStripePayment = functions.firestore * * @see https://stripe.com/docs/payments/accept-a-payment-synchronously#web-confirm-payment */ -exports.confirmStripePayment = functions.firestore +exports.confirmStripePayment = functions.runWith({secrets: [stripeSecret]}).firestore .document('stripe_customers/{userId}/payments/{pushId}') .onUpdate(async (change, context) => { if (change.after.data().status === 'requires_confirmation') { @@ -139,7 +146,7 @@ exports.confirmStripePayment = functions.firestore /** * When a user deletes their account, clean up after them */ -exports.cleanupUser = functions.auth.user().onDelete(async (user) => { +exports.cleanupUser = functions.runWith({secrets: [stripeSecret]}).auth.user().onDelete(async (user) => { const dbRef = admin.firestore().collection('stripe_customers'); const customer = (await dbRef.doc(user.uid).get()).data(); await stripe.customers.del(customer.customer_id); diff --git a/Node-1st-gen/survey-app-update/README.md b/Node-1st-gen/survey-app-update/README.md index 38fb40781..3c1c9ebc5 100644 --- a/Node-1st-gen/survey-app-update/README.md +++ b/Node-1st-gen/survey-app-update/README.md @@ -22,7 +22,14 @@ The function triggers on changes to `app_update` Firebase Analytics events. For Set the `gmail.email` and `gmail.password` Google Cloud environment variables to match the email and password of the Gmail account used to send emails. For this use: ```bash -firebase functions:config:set gmail.email="myusername@gmail.com" gmail.password="secretpassword" +Add the following configuration to your `.env` file: +``` +GMAIL_EMAIL="myusername@gmail.com" +``` +Then, set the `GMAIL_PASSWORD` secret: +``` +firebase functions:secrets:set GMAIL_PASSWORD +``` ``` diff --git a/Node-1st-gen/survey-app-update/functions/index.js b/Node-1st-gen/survey-app-update/functions/index.js index 812cbd6e5..48f4f14cc 100644 --- a/Node-1st-gen/survey-app-update/functions/index.js +++ b/Node-1st-gen/survey-app-update/functions/index.js @@ -16,16 +16,22 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineString, defineSecret} = require('firebase-functions/params'); const admin = require('firebase-admin'); admin.initializeApp(); const nodemailer = require('nodemailer'); // Configure the email transport using the default SMTP transport and a GMail account. // For other types of transports such as Sendgrid see https://nodemailer.com/transports/ -// TODO: Configure the `gmail.email` and `gmail.password` Google Cloud environment variables. -const gmailEmail = encodeURIComponent(functions.config().gmail.email); -const gmailPassword = encodeURIComponent(functions.config().gmail.password); -const mailTransport = nodemailer.createTransport( - `smtps://${gmailEmail}:${gmailPassword}@smtp.gmail.com`); +// TODO: Configure the `GMAIL_EMAIL` environment variable and the `GMAIL_PASSWORD` secret. +const gmailEmail = defineString('GMAIL_EMAIL'); +const gmailPassword = defineSecret('GMAIL_PASSWORD'); + +let mailTransport; +onInit(() => { + mailTransport = nodemailer.createTransport( + `smtps://${encodeURIComponent(gmailEmail.value())}:${encodeURIComponent(gmailPassword.value())}@smtp.gmail.com`); +}); // TODO: Create yor own survey. const LINK_TO_SURVEY = 'https://goo.gl/forms/IdurnOZ66h3FtlO33'; @@ -34,7 +40,7 @@ const LATEST_VERSION = '2.0'; /** * After a user has updated the app. Send them a survey to compare the app with the old version. */ -exports.sendAppUpdateSurvey = functions.analytics.event('app_update').onLog(async (event) => { +exports.sendAppUpdateSurvey = functions.runWith({secrets: [gmailPassword]}).analytics.event('app_update').onLog(async (event) => { const uid = event.user.userId; const appVerion = event.user.appInfo.appVersion; diff --git a/Node-1st-gen/testlab-to-slack/README.md b/Node-1st-gen/testlab-to-slack/README.md index c6c677e9c..2a11eb2b9 100644 --- a/Node-1st-gen/testlab-to-slack/README.md +++ b/Node-1st-gen/testlab-to-slack/README.md @@ -26,7 +26,7 @@ this: authenticate with Slack and post to the correct room: ```bash - firebase functions:config:set slack.webhook_url="YOUR_SLACK_WEBHOOK_URL" + firebase functions:secrets:set SLACK_WEBHOOK_URL ``` ## Deploy and test diff --git a/Node-1st-gen/testlab-to-slack/functions/index.js b/Node-1st-gen/testlab-to-slack/functions/index.js index 832ce0d59..440dc1608 100644 --- a/Node-1st-gen/testlab-to-slack/functions/index.js +++ b/Node-1st-gen/testlab-to-slack/functions/index.js @@ -15,6 +15,9 @@ */ const functions = require('firebase-functions/v1'); +const {defineSecret} = require('firebase-functions/params'); + +const slackWebhookUrl = defineSecret('SLACK_WEBHOOK_URL'); /** * Posts a message to Slack via a Webhook @@ -23,7 +26,7 @@ const functions = require('firebase-functions/v1'); * @return {Promise} */ async function postToSlack(title, details) { - const response = await fetch(process.env.SLACK_WEBHOOK_URL, { + const response = await fetch(slackWebhookUrl.value(), { method: "post", body: JSON.stringify({ blocks: [ @@ -76,7 +79,7 @@ function getSlackmoji(term) { } } -exports.postTestResultsToSlack = functions.testLab +exports.postTestResultsToSlack = functions.runWith({secrets: [slackWebhookUrl]}).testLab .testMatrix() .onComplete(async testMatrix => { const { testMatrixId, state, outcomeSummary } = testMatrix; diff --git a/Node-1st-gen/url-shortener/README.md b/Node-1st-gen/url-shortener/README.md index 3167a9a07..64947b54e 100644 --- a/Node-1st-gen/url-shortener/README.md +++ b/Node-1st-gen/url-shortener/README.md @@ -18,7 +18,7 @@ The dependencies are listed in [functions/package.json](functions/package.json). - Set the sample to use your Firebase project using `firebase use --add` and select your new Firebase project. - Set your Bit.ly app's access token on your function by running: ```bash - firebase functions:config:set bitly.access_token=XXXXXXXXXXXXX + firebase functions:secrets:set BITLY_ACCESS_TOKEN ``` - Deploy the function using `firebase deploy` - Manually add an object to the Realtime Database following the structure described below. diff --git a/Node-1st-gen/url-shortener/functions/index.js b/Node-1st-gen/url-shortener/functions/index.js index c7302da41..5c8b65e61 100644 --- a/Node-1st-gen/url-shortener/functions/index.js +++ b/Node-1st-gen/url-shortener/functions/index.js @@ -16,12 +16,19 @@ 'use strict'; const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const { BitlyClient } = require('bitly'); -// TODO: Make sure to set the bitly.access_token cloud functions config using the CLI. -const bitly = new BitlyClient(functions.config().bitly.access_token); +// TODO: Make sure to set the `BITLY_ACCESS_TOKEN` secret using the CLI. +const bitlyAccessToken = defineSecret('BITLY_ACCESS_TOKEN'); + +let bitly; +onInit(() => { + bitly = new BitlyClient(bitlyAccessToken.value()); +}); // Shorten URL written to /links/{linkID}. -exports.shortenUrl = functions.database.ref('/links/{linkID}').onCreate(async (snap) => { +exports.shortenUrl = functions.runWith({secrets: [bitlyAccessToken]}).database.ref('/links/{linkID}').onCreate(async (snap) => { const originalUrl = snap.val(); const response = await bitly.shorten(originalUrl); // @ts-ignore diff --git a/Node-1st-gen/youtube/README.md b/Node-1st-gen/youtube/README.md index 0767d1005..37517801b 100644 --- a/Node-1st-gen/youtube/README.md +++ b/Node-1st-gen/youtube/README.md @@ -40,7 +40,7 @@ default it will return information about the Firebase CLI, select your Project ID and follow the instructions. 1. Set the YouTube API key as an environment variable: ```bash - firebase functions:config:set youtube.key="THE API KEY" + firebase functions:secrets:set YOUTUBE_KEY ``` ### Run your function locally with the Firebase Emulator Suite @@ -48,8 +48,6 @@ default it will return information about the 1. Set up the Firebase emulators with your config ([docs](https://firebase.google.com/docs/functions/local-emulator#set_up_functions_configuration_optional)): ```bash cd functions - - firebase functions:config:get > .runtimeconfig.json ``` 1. Run the following command to start the emulator: ```bash diff --git a/Node-1st-gen/youtube/functions/index.js b/Node-1st-gen/youtube/functions/index.js index 5e0a64026..7acab580d 100644 --- a/Node-1st-gen/youtube/functions/index.js +++ b/Node-1st-gen/youtube/functions/index.js @@ -15,16 +15,23 @@ */ const functions = require('firebase-functions/v1'); +const {onInit} = require('firebase-functions/v1/init'); +const {defineSecret} = require('firebase-functions/params'); const { google } = require('googleapis'); -const youtube = google.youtube({ - version: 'v3', - auth: functions.config().youtube.key, -}); +const youtubeKey = defineSecret('YOUTUBE_KEY'); const FIREBASE_YOUTUBE_CHANNEL_ID = 'UCP4bf6IHJJQehibu6ai__cg'; -exports.getChannelInfo = functions.https.onRequest( +let youtube; +onInit(() => { + youtube = google.youtube({ + version: 'v3', + auth: youtubeKey.value(), + }); +}); + +exports.getChannelInfo = functions.runWith({secrets: [youtubeKey]}).https.onRequest( async (request, response) => { const channelId = request.query.channelId || FIREBASE_YOUTUBE_CHANNEL_ID;