Class PushProps

All Implemented Interfaces:
EventListener, IGProp<GProp<?>[]>, IPropCnr, ISecretsContext, Cloneable
Direct Known Subclasses:
EditorPushProps

public class PushProps extends PropCnr implements ISecretsContext
The Push properties for the application.

The two secrets live in the secrets store only (CC-PUSH-PWA-PAGES, rulings PP-1 and PP-3): an application's VAPID private key (VAPID_PRIVATE_KEY) and Firebase service account (FCM_SERVICE_ACCOUNT) are secret-marked members whose value is never written into .iiziPush and is taken from this machine's secrets store under app.<appID>/$push/<member> when the loader gives the context (setSecretsContext(String)). An inline value found in the file is dropped at that moment with one WARNING naming the member, never the value, and so is a key file reference (VAPID_PRIVATE_KEY_FILE, FCM_SERVICE_ACCOUNT_FILE), which only the server's own container (application *) still supports. The Designer's Push page generates or imports a secret into the store; iizi-secrets moves it to a production server.

A secret the store does not hold switches the transport off (CC-FIX-PUSH-SECRET-MISSING, ruling T5-D-1): a fresh installation holds no secret of any application, so the absence is a state of this machine, not an error. setSecretsContext(String) says so with ONE WARNING per application - which transports are off, the keys missing, the store read, how to add them - instead of the SEVERE per key of a missing secret (isSecretOptional(GProp)); the engine answers "not configured" for the transport (PushEngine.getTransportState), so nothing is sent for the application and no device is subscribed under its public half. The server's own container keeps the SEVERE.

The server's own $push (the $pushNotifications child of the server configuration, application *) is never given a context by a loader: it takes the context of its nearest ISecretsContext ancestor, the configuration's server.<name>, and its keys are the configuration's, server.<name>/$pushNotifications/$push/<member> (ruling PP-D-2). It is then not a root of its own (isSecretsRoot()): a member marked secret there is resolved and committed with the configuration's own secrets. Its inline pair and its key file references are untouched - the store-only rule above is applied by the loader's setSecretsContext(String) call only, which the server's container never gets.

Author:
Christopher Mindus
  • Field Details

    • FILE_NAME

      public static final String FILE_NAME
      The file name of the Push Notification properties container: ".iiziPush".
      See Also:
    • ATOM

      public static final Atom ATOM
      The atom for the Push Notification properties container: "$push".
    • TTL

      public static final String TTL
      The default Time-to-Live duration property: "TTL".
      See Also:
    • SUBSCRIBE_AT_SIGNIN

      public static final String SUBSCRIBE_AT_SIGNIN
      The "subscribe the device at sign-in" property: "subscribeAtSignIn". A boolean, false by default (CC-PUSH-SUBSCRIBE-AT-SIGNIN, ruled 2026-10-22 LV-D-2): when true, the server subscribes the device of a session to the application-level Topic once a user has signed in to the application - at the session's creation with a signed-in user, or at an in-app sign-in - where otherwise the application's Java calls subscribe itself (ClientSessionPushAPI.subscribeAtSignIn). Off by default: a phone is asked for its permission at the first sign-in, which not every application wants.
      See Also:
    • VAPID_PRIVATE_KEY

      public static final String VAPID_PRIVATE_KEY
      The private key property: "VPrivKey". A SECRET held by this machine's secrets store only (ruling PP-1): the member is marked secret, saved as <string name="VPrivKey" secret="true"/> without a value, and takes its value from the store under app.<appID>/$push/VPrivKey once the loader has given the context. An inline value in .iiziPush is dropped at that moment with one WARNING (ruling PP-3): the file is versioned and compiled into the application's jar, so a key written there travels with both.
      See Also:
    • VAPID_PUBLIC_KEY

      public static final String VAPID_PUBLIC_KEY
      The public key property: "VPubKey".
      See Also:
    • VAPID_SUBJECT

      public static final String VAPID_SUBJECT
      The VAPID subject property: "VSubject". The sub claim of the VAPID JWT (RFC 8292 section 2.1), a mailto: or https: contact URI the push service may use to reach the operator. Optional.
      See Also:
    • FCM_PROJECT_ID

      public static final String FCM_PROJECT_ID
      The Firebase project ID property: "fcmProject". The {project_id} of the FCM HTTP v1 endpoint https://fcm.googleapis.com/v1/projects/{project_id}/messages:send. Public: it is what the client receives as fc and i from /iizi-push/keys.
      See Also:
    • FCM_SERVICE_ACCOUNT

      public static final String FCM_SERVICE_ACCOUNT
      The Firebase service account property: "fcmServiceAccount". The JSON text of a Google service-account key file (client_email, private_key, token_uri, ...) with the Firebase Cloud Messaging API role, from which the server mints the OAuth 2.0 access token that authorizes each FCM v1 send. SECRET: this file is a credential, exactly as VAPID_PRIVATE_KEY is, and is held by the secrets store only, the same way (ruling PP-1): the Designer's Push page imports the downloaded JSON into the store; the file carries the mark and no value.
      See Also:
    • VAPID_PRIVATE_KEY_FILE

      public static final String VAPID_PRIVATE_KEY_FILE
      The VAPID key file property: "VPrivKeyFile". A reference to a key file holding a VAPID pair - a $push container with VPubKey and VPrivKey, the format of the server's own server-keys.iiziPush - written as a path: relative to the key directory of the machine that reads it (iizi.push.keys, IIZI_PUSH_KEYS, else ~/.iizi/push-keys), or absolute, ~ and %NAME% expanded (PUSH-KEYFILES-DESIGN.md sections 2 to 4). Only the server's own container reads it: the credentials file's [server] section and the server settings' $push, application * (PUSH-CREDENTIALS.md 3.6, S-4). An application's .iiziPush does not support it since ruling PP-1: the member is removed at load with a WARNING, and the application's key comes from the secrets store.
      See Also:
    • FCM_SERVICE_ACCOUNT_FILE

      public static final String FCM_SERVICE_ACCOUNT_FILE
      The Firebase service account key file property: "fcmServiceAccountFile". A reference to Google's service-account JSON as the Firebase console downloads it, written as VAPID_PRIVATE_KEY_FILE is; the name the credentials file's [server] section uses. As VAPID_PRIVATE_KEY_FILE: the server's own container only, removed from an application's .iiziPush at load with a WARNING (ruling PP-1).
      See Also:
  • Constructor Details

    • PushProps

      public PushProps()
      Creates a PushProps container without name and with a null value.
    • PushProps

      public PushProps(Atom propertyAtom)
      Creates a PushProps container with the specified name with a null value.
      Parameters:
      propertyAtom - the property atom.
  • Method Details

    • clone

      public PushProps clone()
      Creates a clone out of this property.
      Overrides:
      clone in class PropCnr
      Returns:
      The clone of the PWAProps.
    • getSecretsContext

      public String getSecretsContext()
      Gets the secrets context of the application this .iiziPush belongs to, app.<appID>, as its loader gave it with setSecretsContext(String): the file itself carries no identity (decision SK3-D-3). A container no loader gave a context takes the context of its nearest ISecretsContext ancestor - the server configuration's server.<name> for the server's own $push (ruling PP-D-2).
      Specified by:
      getSecretsContext in interface ISecretsContext
      Returns:
      The context, or null when none was given and no ancestor gives one.
    • isSecretsRoot

      public boolean isSecretsRoot()
      Tells whether this container is a root of its own: when a loader gave it a context, or when no ancestor implements ISecretsContext (an application's .iiziPush before its loader speaks, a VAPID key file). The server's own $push is not: it belongs to the server configuration (ruling PP-D-2).
      Specified by:
      isSecretsRoot in interface ISecretsContext
      Returns:
      true when this container is a root of its own.
    • getSecretsKey

      public String getSecretsKey(GProp<?> prop)
      Gets the key of a secret-marked member: the context, then this container's atom $push, then the member's atom path, e.g. app.com.mindus.icu/$push/VPrivKey. The application's own members are keyed under the same context without it. A container that belongs to an ancestor root answers that root's key: the member's atom path from the root, e.g. server.Test2.config/$pushNotifications/$push/VPrivKey.
      Specified by:
      getSecretsKey in interface ISecretsContext
      Parameters:
      prop - The secret-marked member.
      Returns:
      The key, or null when there is no context or the member is not below this container.
    • setSecretsContext

      public int setSecretsContext(String context)
      Gives this container the secrets context of its application and resolves its secret-marked members from this machine's secrets store, called by the loader once the application is known: AppFactory on the server, the project in iiziGo (decision SK3-D-3). The first call makes the container store-only (rulings PP-1 and PP-3): VAPID_PRIVATE_KEY and FCM_SERVICE_ACCOUNT become secret-marked members without a value - an inline value found in the file is dropped with one WARNING naming the member, never the value - and a key file reference (VAPID_PRIVATE_KEY_FILE, FCM_SERVICE_ACCOUNT_FILE) is removed with one WARNING. The marked members then hold the store's value. A loader that gives no context - an application without an App ID - leaves them unconfigured, reported once. A secret the store does not hold leaves its transport off for the application, said once with a WARNING (isSecretOptional(GProp), ruling T5-D-1). Giving the same context again does nothing.

      The server's own container (application *) and a VAPID key file are never given a context, so their inline pair and their references are untouched.

      Parameters:
      context - The context, e.g. app.com.mindus.icu, null for none.
      Returns:
      The number of members that took a value.
    • isSecretOptional

      public boolean isSecretOptional(GProp<?> prop)
      Tells whether a secret-marked member is optional: an application's two store-only members, VAPID_PRIVATE_KEY and FCM_SERVICE_ACCOUNT, once a loader gave this container its context. Their absence from the store is this machine's configuration - a fresh installation holds no secret of any application - and switches the transport off for the application, which setSecretsContext(String) says once per application; the framework's SEVERE per key is for a secret a configuration cannot do without. The server's own container, which no loader gives a context, keeps that SEVERE for its marked members.
      Specified by:
      isSecretOptional in interface ISecretsContext
      Parameters:
      prop - The secret-marked property.
      Returns:
      true for an application's store-only member.
    • getSecretsKey

      public String getSecretsKey(String member)
      Gets the secrets store key of a member of this container, present or not: <context>/$push/<member>, or, for a container that belongs to an ancestor root, the root's context and this container's atom path from it, server.<name>/$pushNotifications/$push/<member>. The Designer's Push page asks the store about a secret the file does not hold yet.
      Parameters:
      member - The member name, e.g. VAPID_PRIVATE_KEY.
      Returns:
      The key, or null when there is no context.
    • getPublicVAPIDKey

      public String getPublicVAPIDKey()
      Gets the VAPID public key.
      Returns:
      A Base64-encoded String containing an ECDSA P-256 public key that the push server will use to authenticate the server. Returns null if undefined.
    • getPrivateVAPIDKey

      public String getPrivateVAPIDKey()
      Gets the VAPID private key.
      Returns:
      A Base64url-encoded String containing the P-256 private scalar, 32 bytes, that signs the VAPID JWT. Returns null if undefined.
    • getVAPIDSubject

      public String getVAPIDSubject()
      Gets the VAPID subject, i.e. the sub claim of the VAPID JWT.
      Returns:
      A mailto: or https: contact URI, or null if undefined.
    • getFCMProjectID

      public String getFCMProjectID()
      Gets the Firebase project ID for FCM HTTP v1 sends.
      Returns:
      The project ID, or null if FCM is not configured for the application.
    • getFCMServiceAccount

      public String getFCMServiceAccount()
      Gets the Firebase service account key file as JSON text.
      Returns:
      The service account JSON, or null if FCM is not configured.
    • getPrivateVAPIDKeyFile

      public String getPrivateVAPIDKeyFile()
      Gets the reference to the VAPID key file of the server's own container (application *); an application's container holds none (ruling PP-1).
      Returns:
      The reference as written, a relative or absolute path, or null if undefined; com.iizix.push.PushKeyFiles resolves it.
    • getFCMServiceAccountFile

      public String getFCMServiceAccountFile()
      Gets the reference to the Firebase service account key file of the server's own container (application *); an application's container holds none (ruling PP-1).
      Returns:
      The reference as written, or null if undefined.
    • getTTL

      public long getTTL()
      Gets the default Time-to-Live of the application's Push Notifications: the TTL property of .iiziPush, in milliseconds as the Designer's DurationPropEditor stores it. The engine applies it to a send that carries no TTL of its own, for the HTTP push and the Java API alike, clamped into [IPushSettings.TTL_MIN, IPushSettings.TTL_MAX] (PUSH-WIRE-CONTRACT.md section 6.4, P4-03).
      Returns:
      The TTL in milliseconds, or -1 if undefined: the server-wide default (IPushSettings.TTL_DEFAULT, 28 days) then applies.
    • isSubscribeAtSignIn

      public boolean isSubscribeAtSignIn()
      Tells whether the server subscribes the device at sign-in: the SUBSCRIBE_AT_SIGNIN property of .iiziPush (CC-PUSH-SUBSCRIBE-AT-SIGNIN, ruled 2026-10-22 LV-D-2). When true, a session whose user is signed in - at its creation, or by an in-app sign-in - has its device subscribed once to the application-level Topic by the server, through the session's Push Notification channel, as the application's Java would do with subscribe(""): a Cordova device is asked for its permission the first time, a Browser follows only when its permission is already granted (a prompt outside a click is never shown), and a session without a channel to a device is left alone.
      Returns:
      true when the application opted in; false by default, and when undefined.
    • verify

      public boolean verify(PropVerification verification)
      Verifies this property container. The check performed is the extension of classes and that no circular reference is present.
      Specified by:
      verify in interface IGProp<GProp<?>[]>
      Overrides:
      verify in class PropCnr
      Parameters:
      verification - The property verification class.
      Returns:
      true if verification should proceed, false if disposed of and verification should not take place.