ضبط البيئة

غالبًا ما ستحتاج إلى إعدادات إضافية لدوالك، مثل مفاتيح واجهات برمجة التطبيقات التابعة لجهات خارجية أو إعدادات قابلة للضبط. توفر حزمة Firebase SDK لـ Cloud Functions إعدادات بيئة مضمّنة لتسهيل تخزين هذا النوع من البيانات واستردادها لمشروعك.

يمكنك الاختيار من بين الخيارات التالية:

  • الإعدادات المستندة إلى المَعلمات (ننصح بها في معظم الحالات): توفّر هذه الإعدادات إعدادات بيئة ذات أنواع بيانات محددة تتضمّن مَعلمات يتم التحقّق من صحتها في وقت النشر، ما يمنع حدوث الأخطاء ويُبسّط عملية تصحيح الأخطاء.
  • الإعدادات المستندة إلى الملفات لمتغيّرات البيئة: باستخدام هذه الطريقة، يمكنك إنشاء ملف dotenv يدويًا لتحميل متغيّرات البيئة.

ننصح باستخدام الإعدادات المستندة إلى المَعلمات في معظم حالات الاستخدام. تتيح هذه الطريقة قيم الإعدادات في وقت التشغيل ووقت النشر، ويتم حظر النشر ما لم تتضمّن جميع المَعلمات قيمة صالحة. في المقابل، لا تتوفّر الإعدادات باستخدام متغيّرات البيئة في وقت النشر.

الإعدادات المستندة إلى المَعلمات

Cloud Functions for Firebase توفّر واجهة لتعريف مَعلمات الإعدادات بشكل تصريحي داخل قاعدة الرموز البرمجية. تتوفّر قيمة هذه المَعلمات أثناء نشر الدالة، عند ضبط خيارات النشر ووقت التشغيل، وأثناء التنفيذ. هذا يعني أنّ واجهة سطر الأوامر ستحظر النشر ما لم تتضمّن جميع المَعلمات قيمة صالحة.

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineInt, defineString } = require('firebase-functions/params');

// Define some parameters
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")
WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

# To use configured parameters inside the config for a function, provide them
# directly. To use them at runtime, call .value() on them.
@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

عند نشر دالة تتضمّن متغيّرات إعدادات مستندة إلى المَعلمات، تحاول واجهة سطر الأوامر في Firebase أولاً تحميل قيمها من ملفات ‎ .env محلية. إذا لم تكن هذه القيم متوفّرة في هذه الملفات ولم يتم ضبط default، ستطلب واجهة سطر الأوامر القيم أثناء النشر، ثم تحفظ قيمها تلقائيًا في ملف .env باسم .env.<project_ID> في دليل functions/:

$ firebase deploy
i  functions: preparing codebase default for deployment
? Enter a string value for ENVIRONMENT: prod
i  functions: Writing new parameter values to disk: .env.projectId
…
$ firebase deploy
i  functions: Loaded environment variables from .env.projectId

استنادًا إلى سير عمل التطوير، قد يكون من المفيد إضافة الملف الذي تم إنشاؤه .env.<project_ID> إلى نظام التحكّم في الإصدار.

استخدام المَعلمات في النطاق العام

أثناء النشر، يتم تحميل رمز الدوال وفحصه قبل أن تتضمّن المَعلمات قيمًا فعلية. هذا يعني أنّ جلب قيم المَعلمات أثناء النطاق العام يؤدي إلى فشل النشر. في الحالات التي تريد فيها استخدام مَعلمة لتهيئة قيمة عامة، استخدِم معاودة الاتصال الخاصة بالتهيئة onInit(). يتم تشغيل معاودة الاتصال هذه قبل تشغيل أي دوال في مرحلة الإنتاج، ولكن لا يتم استدعاؤها أثناء وقت النشر، لذا فهي مكان آمن للوصول إلى قيمة المَعلمة.

Node.js

const { GoogleGenerativeAI } = require('@google/generative-ai');
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v2/core');

const apiKey = defineSecret('GOOGLE_API_KEY');

let genAI;
onInit(() => {
  genAI = new GoogleGenerativeAI(apiKey.value());
})

Python

from firebase_functions.core import init
from firebase_functions.params import StringParam, PROJECT_ID
import firebase_admin
import vertexai

location = StringParam("LOCATION")

x = "hello"

@init
def initialize():
  # Note: to write back to a global, you'll need to use the "global" keyword
  # to avoid creating a new local with the same name.
  global x
  x = "world"
  firebase_admin.initialize_app()
  vertexai.init(PROJECT_ID.value, location.value)

إذا كنت تستخدم مَعلمات من النوع Secret، يُرجى العِلم أنّها لا تتوفّر إلا في عملية الدوال التي تم ربط السرّ بها. إذا تم ربط سرّ في بعض الدوال فقط، تحقَّق مما إذا كانت قيمة secret.value() غير صحيحة قبل استخدامها.

ضبط سلوك واجهة سطر الأوامر

يمكن ضبط المَعلمات باستخدام كائن Options يتحكّم في كيفية طلب واجهة سطر الأوامر للقيم. يضبط المثال التالي الخيارات للتحقّق من صحة تنسيق رقم الهاتف، وتوفير خيار اختيار بسيط، وتعبئة خيار اختيار تلقائيًا من مشروع Firebase:

Node.js

const { defineString } = require('firebase-functions/params');

const welcomeMessage = defineString('WELCOME_MESSAGE', {default: 'Hello World',
description: 'The greeting that is returned to the caller of this function'});

const onlyPhoneNumbers = defineString('PHONE_NUMBER', {
  input: {
    text: {
      validationRegex: /\d{3}-\d{3}-\d{4}/,
      validationErrorMessage: "Please enter
a phone number in the format XXX-YYY-ZZZZ"
    },
  },
});

const selectedOption = defineString('PARITY', {input: params.select(["odd", "even"])});

const memory = defineInt("MEMORY", {
  description: "How much memory do you need?",
  input: params.select({ "micro": 256, "chonky": 2048 }),
});

const extensions = defineList("EXTENSIONS", {
  description: "Which file types should be processed?",
  input: params.multiSelect(["jpg", "tiff", "png", "webp"]),
});

const storageBucket = defineString('BUCKET', {
  description: "This will automatically
populate the selector field with the deploying Cloud Project’s
storage buckets",
  input: params.PICK_STORAGE_BUCKET,
});

Python

from firebase_functions.params import (
    StringParam,
    ListParam,
    TextInput,
    SelectInput,
    SelectOptions,
    ResourceInput,
    ResourceType,
)

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

WELCOME_MESSAGE = StringParam(
    "WELCOME_MESSAGE",
    default="Hello World",
    description="The greeting that is returned to the caller of this function",
)

ONLY_PHONE_NUMBERS = StringParam(
    "PHONE_NUMBER",
    input=TextInput(
        validation_regex="\d{3}-\d{3}-\d{4}",
        validation_error_message="Please enter a phone number in the format XXX-YYY-XXX",
    ),
)

SELECT_OPTION = StringParam(
    "PARITY",
    input=SelectInput([SelectOptions(value="odd"), SelectOptions(value="even")]),
)

STORAGE_BUCKET = StringParam(
    "BUCKET",
    input=ResourceInput(type=ResourceType.STORAGE_BUCKET),
    description="This will automatically populate the selector field with the deploying Cloud Project's storage buckets",
)

أنواع المَعلمات

توفّر الإعدادات المستندة إلى المَعلمات أنواع بيانات محددة لقيم المَعلمات، وتتوافق أيضًا مع الأسرار من Cloud Secret Manager. الأنواع المتوافقة هي:

  • سري
  • سلسلة
  • قيمة منطقية
  • عدد صحيح
  • عائم
  • قائمة (Node.js)
  • سر JSON ‏ (Node.js)

يُرجى الاطّلاع على مرجع مساحة الاسم params للحصول على معلومات عن الدوال الخاصة بتحديد المَعلمات.

قيم المَعلمات والتعبيرات

تقيِّم Firebase مَعلماتك في وقت النشر وأثناء تنفيذ الدالة. بسبب هاتين البيئتين المزدوجتين، يجب توخي الحذر عند مقارنة قيم المَعلمات، وعند استخدامها لضبط خيارات وقت التشغيل لدوالك.

لتمرير مَعلمة إلى الدالة كخيار وقت التشغيل، مرِّرها مباشرةً:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineInt } = require('firebase-functions/params');
const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');

export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
  (req, res) => {
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam

MIN_INSTANCES = IntParam("HELLO_WORLD_MIN_INSTANCES")

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

بالإضافة إلى ذلك، إذا كنت بحاجة إلى المقارنة بمَعلمة لمعرفة الخيار الذي يجب اختياره، عليك استخدام عوامل المقارنة المضمّنة بدلاً من التحقّق من القيمة:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const environment = params.defineString(ENVIRONMENT, {default: 'dev'});

// use built-in comparators
const minInstancesConfig = environment.equals('PRODUCTION').thenElse(10, 1);
export const helloWorld = onRequest(
  { minInstances: minInstancesConfig },
  (req, res) => {
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import IntParam, StringParam

ENVIRONMENT = StringParam("ENVIRONMENT", default="dev")
MIN_INSTANCES = ENVIRONMENT.equals("PRODUCTION").then(10, 0)

@https_fn.on_request(min_instances=MIN_INSTANCES)
def hello_world(req):
    ...

يمكن الوصول إلى المَعلمات وتعبيرات المَعلمات التي لا تُستخدَم إلا في وقت التشغيل باستخدام دالة value الخاصة بها:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineString } = require('firebase-functions/params');
const welcomeMessage = defineString('WELCOME_MESSAGE');

// To use configured parameters inside the config for a function, provide them
// directly. To use them at runtime, call .value() on them.
export const helloWorld = onRequest(
(req, res) => {
    res.send(`${welcomeMessage.value()}! I am a function.`);
  }
);

Python

from firebase_functions import https_fn
from firebase_functions.params import StringParam

WELCOME_MESSAGE = StringParam("WELCOME_MESSAGE")

@https_fn.on_request()
def hello_world(req):
    return https_fn.Response(f'{WELCOME_MESSAGE.value()}! I am a function!')

المَعلمات المضمّنة

توفّر حزمة Cloud Functions SDK ثلاث مَعلمات محدّدة مسبقًا، تتوفّر من الحزمة الفرعية firebase-functions/params:

Node.js

  • projectID: مشروع على السحابة الإلكترونية الذي يتم تشغيل الدالة فيه
  • databaseURL : عنوان URL لمثيل قاعدة بيانات الوقت الفعلي المرتبط بالدالة (إذا كانت هذه الخدمة مفعّلة في مشروع Firebase)
  • storageBucket : مجموعة Cloud Storage المرتبطة بالدالة (إذا كانت هذه الخدمة مفعّلة في مشروع Firebase)

Python

  • PROJECT_ID: مشروع على السحابة الإلكترونية الذي يتم تشغيل الدالة فيه
  • DATABASE_URL : عنوان URL لمثيل قاعدة بيانات الوقت الفعلي المرتبط بالدالة (إذا كانت هذه الخدمة مفعّلة في مشروع Firebase)
  • STORAGE_BUCKET : مجموعة Cloud Storage المرتبطة بالدالة (إذا كانت هذه الخدمة مفعّلة في مشروع Firebase)

تشبه هذه الدوال مَعلمات السلسلة التي يحدّدها المستخدم من جميع الجوانب، باستثناء أنّه بما أنّ قيمها معروفة دائمًا لواجهة سطر الأوامر في Firebase، لن يُطلب منك إدخال قيمها عند النشر ولن يتم حفظها في ملفات ‎.env.

مَعلمات السرّ

تمثّل المَعلمات من النوع Secret، التي تم تحديدها باستخدام defineSecret()، مَعلمات سلسلة تتضمّن قيمة مخزّنة في Cloud Secret Manager. بدلاً من التحقّق من ملف ‎.env محلي وكتابة قيمة جديدة في الملف إذا كانت غير متوفّرة، تتحقّق مَعلمات السرّ من وجودها في Cloud Secret Manager، وتطلب بشكل تفاعلي قيمة سرّ جديد أثناء النشر.

يجب ربط مَعلمات السرّ بدوال فردية يجب أن تتمكّن من الوصول إليها:

Node.js

const { onRequest } = require('firebase-functions/v2/https');
const { defineSecret } = require('firebase-functions/params');
const discordApiKey = defineSecret('DISCORD_API_KEY');

export const postToDiscord = onRequest(
  { secrets: [discordApiKey] },
  (req, res) => {
  const apiKey = discordApiKey.value();
    //…

Python

from firebase_functions import https_fn
from firebase_functions.params import SecretParam

DISCORD_API_KEY = SecretParam('DISCORD_API_KEY')

@https_fn.on_request(secrets=[DISCORD_API_KEY])
def post_to_discord(req):
    api_key = DISCORD_API_KEY.value

بما أنّ قيم الأسرار تكون مخفية إلى أن يتم تنفيذ الدالة، لا يمكنك استخدامها أثناء ضبط الدالة.

أسرار JSON منظَّمة

إذا كان لديك عدة قيم إعدادات مرتبطة منطقيًا (على سبيل المثال، إعدادات لخدمة تابعة لجهة خارجية)، يمكنك تخزينها معًا ككائن JSON منظَّم ضمن سرّ واحد باستخدام defineJsonSecret(). يمكن أن تساعد هذه الطريقة في تنظيم إعداداتك وتحقيق استخدام أكثر فعالية للمستوى المجاني من Cloud Secret Manager من خلال تخزين مجموعة من قيم الإعدادات ذات الصلة في سرّ واحد.

يجب أن تكون القيمة المخزّنة في Secret Manager سلسلة JSON صالحة. ستحلّل حزمة SDK تلقائيًا سلسلة JSON إلى كائن JavaScript عند الوصول إلى .value().

مثال:

const { onRequest } = require('firebase-functions/v2/https');
const { defineJsonSecret } = require('firebase-functions/params');

// Define a single secret to hold all configuration for some API
const someApiConfig = defineJsonSecret('SOMEAPI_CONFIG');

exports.myApi = onRequest(
  { secrets: [someApiConfig] },
  (req, res) => {
    // someApiConfig.value() automatically parses the JSON secret
    const { apiKey, webhookSecret, clientId } = someApiConfig.value();

    // Now you can use apiKey, webhookSecret, clientId
    // ...
  }
);

لإنشاء السرّ SOMEAPI_CONFIG، عليك ضبط قيمته في Secret Manager على سلسلة JSON مثل:

{
  "apiKey": "key_...",
  "webhookSecret": "secret_...",
  "clientId": "client_..."
}

إذا لم تكن قيمة السرّ JSON صالحة، سيؤدي الوصول إلى someApiConfig.value() إلى طرح خطأ في وقت التشغيل.

متغيّرات البيئة

Cloud Functions for Firebase تتوافق مع تنسيق ملف dotenv لتحميل متغيّرات البيئة المحدّدة في ملف .env إلى وقت تشغيل تطبيقك. بعد النشر، يمكن قراءة متغيّرات البيئة من خلال واجهة process.env (في المشاريع المستندة إلى Node.js) أو os.environ (في المشاريع المستندة إلى Python).

لضبط بيئتك بهذه الطريقة، أنشئ ملف ‎.env في مشروعك، وأضِف المتغيّرات المطلوبة، ثم انشر:

  1. أنشئ ملف ‎.env في دليل functions/:

    # Directory layout:
    #   my-project/
    #     firebase.json
    #     functions/
    #       .env
    #       package.json
    #       index.js
    
  2. افتح ملف ‎.env للتعديل، وأضِف المفاتيح المطلوبة. على سبيل المثال:

    PLANET=Earth
    AUDIENCE=Humans
    
  3. انشر الدوال وتأكَّد من تحميل متغيّرات البيئة:

    firebase deploy --only functions
    # ...
    # i functions: Loaded environment variables from .env.
    # ...
    

بعد نشر متغيّرات البيئة المخصّصة، يمكن لرمز الدالة الوصول إليها:

Node.js

// Responds with "Hello Earth and Humans"
exports.hello = onRequest((request, response) => {
  response.send(`Hello ${process.env.PLANET} and ${process.env.AUDIENCE}`);
});

Python

import os

@https_fn.on_request()
def hello(req):
    return https_fn.Response(
        f"Hello {os.environ.get('PLANET')} and {os.environ.get('AUDIENCE')}"
    )

نشر مجموعات متعددة من متغيّرات البيئة

إذا كنت بحاجة إلى مجموعة بديلة من متغيّرات البيئة لمشاريع Firebase (مثل مرحلة الاختبار مقابل مرحلة الإنتاج)، أنشئ ملف .env.<project or alias> واكتب متغيّرات البيئة الخاصة بمشروعك فيه. سيتم تضمين متغيّرات البيئة من ملفات ‎.env وملفات ‎.env الخاصة بالمشروع (إن وُجدت) في جميع الدوال المنشورة.

على سبيل المثال، يمكن أن يتضمّن المشروع هذه الملفات الثلاثة التي تحتوي على قيم مختلفة قليلاً لمرحلة التطوير ومرحلة الإنتاج:

.env .env.dev .env.prod
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Prod Humans

بالنظر إلى القيم في هذه الملفات المنفصلة، ستختلف مجموعة متغيّرات البيئة التي يتم نشرها مع الدوال استنادًا إلى مشروعك المستهدَف:

$ firebase use dev
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.dev.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Dev Humans

$ firebase use prod
$ firebase deploy --only functions
i functions: Loaded environment variables from .env, .env.prod.
# Deploys functions with following user-defined environment variables:
#   PLANET=Earth
#   AUDIENCE=Prod Humans

متغيّرات البيئة المحجوزة

بعض مفاتيح متغيّرات البيئة محجوزة للاستخدام الداخلي. يُرجى عدم استخدام أي من هذه المفاتيح في ملفات ‎.env:

  • جميع المفاتيح التي تبدأ بـ X_GOOGLE_
  • جميع المفاتيح التي تبدأ بـ EXT_
  • جميع المفاتيح التي تبدأ بـ FIREBASE_
  • أي مفتاح من القائمة التالية:
  • CLOUD_RUNTIME_CONFIG
  • ENTRY_POINT
  • GCP_PROJECT
  • GCLOUD_PROJECT
  • GOOGLE_CLOUD_PROJECT
  • FUNCTION_TRIGGER_TYPE
  • FUNCTION_NAME
  • FUNCTION_MEMORY_MB
  • FUNCTION_TIMEOUT_SEC
  • FUNCTION_IDENTITY
  • FUNCTION_REGION
  • FUNCTION_TARGET
  • FUNCTION_SIGNATURE_TYPE
  • K_SERVICE
  • K_REVISION
  • PORT
  • K_CONFIGURATION

تخزين معلومات الإعدادات الحساسة والوصول إليها

يمكن استخدام متغيّرات البيئة المخزّنة في ملفات ‎.env لإعداد الدوال، ولكن يجب ألا تعتبرها طريقة آمنة لتخزين المعلومات الحساسة، مثل بيانات اعتماد قاعدة البيانات أو مفاتيح واجهة برمجة التطبيقات. ويُعدّ ذلك مهمًا بشكل خاص إذا كنت تُحمِّل ملفات ‎.env إلى نظام التحكّم في المصدر.

لمساعدتك في تخزين معلومات الإعدادات الحساسة، Cloud Functions for Firebase تتكامل مع Google Cloud Secret Manager. تخزِّن هذه الخدمة المشفّرة قيم الإعدادات بأمان، مع السماح بالوصول إليها بسهولة من الدوال عند الحاجة.

إنشاء سر واستخدامه

لإنشاء سر، استخدِم واجهة سطر الأوامر Firebase.

لإنشاء سر واستخدامه، اتّبِع الخطوات التالية:

  1. من جذر دليل مشروع على جهاز المستخدم، نفِّذ الأمر التالي:

    firebase functions:secrets:set SECRET_NAME

  2. أدخِل قيمة لـ SECRET_NAME.

    تعرض واجهة سطر الأوامر رسالة نجاح وتحذّر من أنّه يجب نشر الدوال ليصبح التغيير ساريًا.

  3. قبل النشر، تأكَّد من أنّ رمز الدوال يسمح للدالة بالوصول إلى السرّ باستخدام الخيار secrets:

    Node.js

    const { onRequest } = require('firebase-functions/v2/https');
    
    exports.processPayment = onRequest(
      { secrets: ["SECRET_NAME"] },
      (req, res) => {
        const myBillingService = initializeBillingService(
          // reference the secret value
          process.env.SECRET_NAME
        );
        // Process the payment
      }
    );

    Python

    import os
    from firebase_functions import https_fn
    
    @https_fn.on_request(secrets=["SECRET_NAME"])
    def process_payment(req):
        myBillingService = initialize_billing(key=os.environ.get('SECRET_NAME'))
        # Process the payment
        ...
    
  4. انشر Cloud Functions:

    firebase deploy --only functions

    سيصبح بإمكانك الآن الوصول إليه مثل أي متغيّر بيئة آخر. في المقابل، إذا حاولت دالة أخرى لا تحدّد السرّ الوصول إليه، ستتلقّى قيمة غير محدّدة:

    Node.js

    exports.anotherEndpoint = onRequest((request, response) => {
      response.send(`The secret API key is ${process.env.SECRET_NAME}`);
      // responds with "The secret API key is undefined" because the `secrets` option is missing
    });
    

    Python

    @https_fn.on_request()
    def another_endpoint(req):
        return https_fn.Response(f"The secret API key is {os.environ.get("SECRET_NAME")}")
        # Responds with "The secret API key is None" because the `secrets` parameter is missing.
    

بعد نشر الدالة، سيصبح بإمكانها الوصول إلى قيمة السرّ. لن تتمكّن من الوصول إلى هذا السرّ كمتغيّر بيئة إلا الدوال التي تتضمّن سرًا بشكلٍ محدّد في خيار secrets. يساعدك ذلك في التأكّد من أنّ قيم الأسرار لا تتوفّر إلا في الأماكن التي تحتاج إليها، ما يقلّل من خطر تسرّب سرّ عن طريق الخطأ.

إدارة الأسرار

استخدِم واجهة سطر الأوامر في Firebase لإدارة أسرارك. أثناء إدارة الأسرار بهذه الطريقة، يُرجى العِلم أنّ بعض تغييرات واجهة سطر الأوامر تتطلّب تعديل الدوال المرتبطة و/أو إعادة نشرها. ونخصّ بالذكر ما يلي:

  • في كل مرة تضبط فيها قيمة جديدة لسرّ، عليك إعادة نشر جميع الدوال التي تشير إلى هذا السرّ لكي تحصل على أحدث قيمة.
  • إذا حذفت سرًا، تأكَّد من أنّ أيًا من الدوال المنشورة لا يشير إلى هذا السرّ. ستفشل الدوال التي تستخدم قيمة سرّ تم حذفه بدون إشعارك بذلك.

في ما يلي ملخّص لأوامر واجهة سطر الأوامر Firebase لإدارة الأسرار:

# Change the value of an existing secret
firebase functions:secrets:set SECRET_NAME

# Set secret from file
firebase functions:secrets:set SECRET_NAME --data-file file.json

# Validate secret value as json
cat file.json | firebase functions:secrets:set SECRET_NAME --format=json

# Pipe from stdin and set secret
cat file.json | firebase functions:secrets:set SECRET_NAME --format=json

# View the value of a secret
functions:secrets:access SECRET_NAME

# Destroy a secret
functions:secrets:destroy SECRET_NAME

# View all secret versions and their state
functions:secrets:get SECRET_NAME

# Automatically clean up all secrets that aren't referenced by any of your functions
functions:secrets:prune

بالنسبة إلى الأمرَين access وdestroy، يمكنك تقديم مَعلمة الإصدار الاختيارية لإدارة إصدار معيّن. على سبيل المثال:

functions:secrets:access SECRET_NAME[@VERSION]

لمزيد من المعلومات حول هذه العمليات، مرِّر الرمز -h مع الأمر لعرض تعليمات واجهة سطر الأوامر.

كيفية فوترة الأسرار

يسمح Secret Manager بـ 6 إصدارات نشطة من الأسرار بدون أي تكلفة. هذا يعني أنّه يمكنك الحصول على 6 أسرار شهريًا في مشروع Firebase بدون أي تكلفة.

تحاول واجهة سطر الأوامر في Firebase تلقائيًا إتلاف إصدارات الأسرار غير المستخدَمة عند الاقتضاء، مثلاً عند نشر الدوال باستخدام إصدار جديد من السرّ. يمكنك أيضًا تنظيف الأسرار غير المستخدَمة بشكل نشط باستخدام functions:secrets:destroy وfunctions:secrets:prune.

Secret Manager يسمح بـ 10,000 عملية وصول شهرية غير مفوترة إلى سرّ. لا تقرأ مثيلات الدوال إلا الأسرار المحدّدة في خيار secrets في كل مرة تبدأ فيها التشغيل على البارد. إذا كان لديك الكثير من مثيلات الدوال التي تقرأ الكثير من الأسرار، قد يتجاوز مشروعك هذا الحد المسموح به، وفي هذه الحالة سيتم تحصيل 0.03 دولار أمريكي لكل 10,000 عملية وصول.

لمزيد من المعلومات، يُرجى الاطّلاع على Secret Manager الأسعار.

التوافق مع المحاكي

تم تصميم إعدادات البيئة باستخدام dotenv للتوافق مع محاكي محلي Cloud Functions.

عند استخدام محاكي Cloud Functions محلي، يمكنك إلغاء متغيّرات البيئة لمشروعك من خلال إعداد ملف .env.local تكون أولوية محتويات ملف .env.local أعلى من ملف .env وملف .env الخاص بالمشروع.

على سبيل المثال، يمكن أن يتضمّن المشروع هذه الملفات الثلاثة التي تحتوي على قيم مختلفة قليلاً لمرحلة التطوير والاختبار المحلي:

.env .env.dev .env.local
PLANET=Earth

AUDIENCE=Humans

AUDIENCE=Dev Humans AUDIENCE=Local Humans

عند بدء المحاكي في السياق المحلي، يتم تحميل متغيّرات البيئة كما هو موضّح:

  $ firebase emulators:start
  i  emulators: Starting emulators: functions
  # Starts emulator with following environment variables:
  #  PLANET=Earth
  #  AUDIENCE=Local Humans

الأسرار وبيانات الاعتماد في محاكي Cloud Functions

يتوافق محاكي Cloud Functions مع استخدام الأسرار لتخزين معلومات الإعدادات الحساسة والوصول إليها . تلقائيًا، سيحاول المحاكي الوصول إلى أسرار الإنتاج باستخدام بيانات الاعتماد التلقائية للتطبيق. في حالات معيّنة، مثل بيئات التكامل المستمر، قد يتعذّر على المحاكي الوصول إلى قيم الأسرار بسبب قيود الأذونات.

على غرار توافق Cloud Functions مع متغيّرات البيئة، يمكنك إلغاء قيم الأسرار من خلال إعداد ملف .secret.local. يسهّل ذلك اختبار الدوال محليًا، خاصةً إذا لم يكن بإمكانك الوصول إلى قيمة السرّ.

نقل البيانات من إعدادات وقت التشغيل

تم إيقاف واجهة برمجة التطبيقات functions.config نهائيًا وسيتم إيقافها نهائيًا في مارس 2027. بعد هذا التاريخ، ستفشل عمليات النشر باستخدام functions.config.

لمنع حالات فشل النشر، عليك نقل إعداداتك إلى Cloud Secret Manager باستخدام واجهة سطر الأوامر في Firebase. ننصح بشدة بهذه الطريقة لأنّها الطريقة الأكثر فعالية وأمانًا لنقل إعداداتك.

  1. تصدير الإعدادات باستخدام واجهة سطر الأوامر في Firebase

    استخدِم الأمر config export لتصدير إعدادات البيئة الحالية إلى سرّ جديد في Cloud Secret Manager:

    $ firebase functions:config:export
    i  This command retrieves your Runtime Config values (accessed via functions.config())
       and exports them as a Secret Manager secret.
    
    i  Fetching your existing functions.config() from your project...     Fetched your existing functions.config().
    
    i  Configuration to be exported:
    ⚠  This may contain sensitive data. Do not share this output.
    
    {
       ...
    } What would you like to name the new secret for your configuration? RUNTIME_CONFIG
    
    ✔  Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```
    
  2. تعديل رمز الدالة لربط الأسرار

    لاستخدام الإعدادات المخزّنة في السرّ الجديد في Cloud Secret Manager، استخدِم واجهة برمجة التطبيقات defineJsonSecret في مصدر الدالة. تأكَّد أيضًا من ربط الأسرار بجميع الدوال التي تحتاج إليها.

    قبل

    const functions = require("firebase-functions/v1");
    
    exports.myFunction = functions.https.onRequest((req, res) => {
      const apiKey = functions.config().someapi.key;
      // ...
    });
    

    بعد

    const { onRequest } = require("firebase-functions/v2/https");
    const { defineJsonSecret } = require("firebase-functions/params");
    
    const config = defineJsonSecret("RUNTIME_CONFIG");
    
    exports.myFunction = onRequest(
      // Bind secret to your function
      { secrets: [config] },
      (req, res) => {
        // Access secret values via .value()
        const apiKey = config.value().someapi.key;
        // ...
    });
    
  3. تفعيل الوظائف

    انشر الدوال المعدَّلة لتطبيق التغييرات وربط أذونات السرّ.

    firebase deploy --only functions:<your-function-name>
    

متغيّرات البيئة التي تتم تعبئتها تلقائيًا

تتوفّر متغيّرات بيئة تتم تعبئتها تلقائيًا في وقت تشغيل الدوال وفي الدوال التي يتم محاكاتها محليًا. ويشمل ذلك المتغيّرات التي تعبئها Google Cloud، بالإضافة إلى متغيّر بيئة خاص بـ Firebase:

process.env.FIREBASE_CONFIG: يوفّر معلومات إعدادات مشروع Firebase التالية:

{
  databaseURL: 'https://DATABASE_NAME.firebaseio.com',
  storageBucket: 'PROJECT_ID.firebasestorage.app',
  projectId: 'PROJECT_ID'
}

يُرجى العِلم أنّ القيم في إعدادات Firebase الفعلية قد تختلف استنادًا إلى الموارد التي تم توفيرها في مشروعك.

يتم تطبيق هذه الإعدادات تلقائيًا عند تهيئة Firebase Admin SDK بدون أي وسيطات. إذا كنت تكتب الدوال بلغة JavaScript، يمكنك تهيئتها على النحو التالي:

const admin = require('firebase-admin');
admin.initializeApp();

إذا كنت تكتب الدوال بلغة TypeScript، يمكنك تهيئتها على النحو التالي:

import * as functions from 'firebase-functions/v1';
import * as admin from 'firebase-admin';
import 'firebase-functions/v1';
admin.initializeApp();

إذا كنت بحاجة إلى تهيئة Admin SDK باستخدام إعدادات المشروع التلقائية باستخدام بيانات اعتماد حساب الخدمة، يمكنك تحميل بيانات الاعتماد من ملف وإضافتها إلى FIREBASE_CONFIG على النحو التالي:

serviceAccount = require('./serviceAccount.json');

const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);