Gestión de cuentas

En esta sección, aprenderá a administrar la cuenta de aJami: crear una cuenta, modificar su configuración básica y eliminar una cuenta. Esta sección no cubre el significado de cada configuración individual o el uso de la cuenta para realizar acciones como agregar contactos.

¿Qué es una cuenta?

En Jami, una cuenta está representada por una cadena de certificados X.509 compuesta por tres certificados:

  1. CA: Un certificado autofirmado si se genera localmente o lo emite una empresa.

  2. Cuenta: Contiene la clave pública, su huella dactilar sirve como Jami ID.

  3. Dispositivo: Asociado a la cuenta.

Nota

Esta estructura permite a una empresa revocar una cuenta completa si es necesario, y permite al propietario de una cuenta revocar dispositivos individuales (por ejemplo, si se roba un dispositivo).

Crear una Cuenta Nueva

Nueva cuenta-daemon API

El ConfigurationManager API (cx.ring.Ring.ConfigurationManager) proporciona el método addAccount:

<method name="addAccount" tp:name-for-bindings="addAccount">
    <tp:docstring>
        Add a new account. When created, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure.
        <tp:rationale>If no details are specified, the default parameters are used.</tp:rationale>
        <tp:rationale>The core tries to register the account as soon it is created.</tp:rationale>
    </tp:docstring>
    <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="MapStringString"/>
    <arg type="a{ss}" name="details" direction="in"  tp:type="String_String_Map">
        <tp:docstring>
             The new account settings
        </tp:docstring>
    </arg>
    <arg type="s" name="createdAccountId" direction="out">
        <tp:docstring>
             A new account ID
        </tp:docstring>
    </arg>
</method>

Nueva cuenta-implementación básica

La lógica central para la creación de cuentas reside en “src/account_factory.cpp”, dentro del método “AccountFactory:: createAccount”`

std::shared_ptr<Account>
AccountFactory::createAccount(std::string_view accountType, const std::string& id)
{
    if (hasAccount(id)) {
        JAMI_ERROR("Existing account {}", id);
        return nullptr;
    }

    const auto& it = generators_.find(accountType);
    if (it == generators_.cend())
        return {};

    std::shared_ptr<Account> account = it->second(id);
    {
        std::lock_guard lock(mutex_);
        auto m = accountMaps_.find(accountType);
        if (m == accountMaps_.end())
            m = accountMaps_.emplace(std::string(accountType), AccountMap<Account>{}).first;
        m->second.emplace(id, account);
    }
    return account;
}

Después de llamar a “addAccount” (o createAccount a través de AccountFactory), se emite la señal “accountsChanged”` Los clientes deben manejar esta señal e invocar “getAccountList” para actualizar su estado local.

Formato de archivo interno

Cuando se crea una cuenta, sus datos se almacenan en un archivo gzip. Si se proporciona una contraseña, el archivo se cifra con AES: dht::crypto::aesEncrypt(archive, password) (dht::crypto::aesEncrypt is defined in OpenDHT and use nettle/{aes,gcm}).. Dentro del archivo, encontrará un archivo JSON que contiene:

  1. The private key ringAccountKey and certificate chain ringAccountCert, base64 encoded.

  2. The generated CA key ringCAKey.

  3. The certificate revocation list for devices ringAccountCRL.

  4. The contact list.

  5. Las configuraciones de la cuenta

Deleting an account

Deleting a Jami account is straightforward: since all key material resides on the local device, removing those key files effectively deletes the account. The only external record is the account’s username on the name server, which may persist depending on the server’s policies (for example, https://ns.jami.net does not currently support remote name deletion).

Delete account—daemon API

The ConfigurationManager API provides the removeAccount method:

<method name="removeAccount" tp:name-for-bindings="removeAccount">
    <tp:docstring>
        Remove an existing account. When removed, the signal <tp:member-ref>accountsChanged</tp:member-ref> is emitted. The clients must then call <tp:member-ref>getAccountList</tp:member-ref> to update their internal data structure.
    </tp:docstring>
    <arg type="s" name="accoundID" direction="in">
        <tp:docstring>
             The account to remove, identified by its ID
        </tp:docstring>
    </arg>
</method>

Cuando se elimina la cuenta, se emitirá la señal accountsChanged. El cliente debe actualizar su estructura interna después de esta señal con otros métodos en ConfigurationManager.

Delete account—core implementation

The core removal logic is in src/accout_factory.cpp (AccountFactory::removeAccount), which deletes the account files and updates the dring.yml configuration.

void
AccountFactory::removeAccount(Account& account)
{
    std::string_view account_type = account.getAccountType();
    std::lock_guard lock(mutex_);
    const auto& id = account.getAccountID();
    JAMI_DEBUG("Removing account {:s}", id);
    auto m = accountMaps_.find(account_type);
    if (m != accountMaps_.end()) {
        m->second.erase(id);
        JAMI_DEBUG("Remaining {:d} {:s} account(s)", m->second.size(), account_type);
    }
}

Updating the details of an account

Update account—daemon API

The ConfigurationManager API provides the setAccountDetails method:

<method name="setAccountDetails" tp:name-for-bindings="setAccountDetails">
    <tp:docstring>
        Send new account parameters, or account parameters changes, to the core. The hash table is not required to be complete, only the updated parameters may be specified.
        <tp:rationale>Account settings are written to the configuration file when the app properly quits.</tp:rationale>
        <tp:rationale>After calling this method, the core will emit the signal <tp:member-ref>accountDetailsChanged</tp:member-ref> with the updated data. The client must subscribe to this signal and use it to update its internal data structure.</tp:rationale>
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="MapStringString"/>
    <arg type="a{ss}" name="details" direction="in" tp:type="String_String_Map">
    </arg>
</method>

El mapa puede contener una actualización parcial y se emitirá accountDetailsChanged al tener éxito. getAccountDetails

Manage Devices

Añadir un dispositivo

There are two methods to add a device to an existing account.

1. Restore from Backup Archive

Use exportToFile to extract the account archive to a local path:

<method name="exportToFile" tp:name-for-bindings="exportToFile">
    <tp:added version="5.1.0"/>
    <tp:docstring>
        Copy the account archive to the path provided in argument.
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="destinationPath" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was initialized successfully.
        </tp:docstring>
    </arg>
</method>

2. Export on the DHT network

Use exportOnRing to publish the encrypted archive on the DHT and obtain a PIN:

<method name="exportOnRing" tp:name-for-bindings="exportOnRing">
    <tp:docstring>
        Export account on the DHT using the given password and generated PIN (returned through exportOnRingEnded signal).
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was initialized successfully. exportOnRingEnded will be trigered on completion.
        </tp:docstring>
    </arg>
</method>

Then exportOnRingEnded is emitted. Clients must listen for the signal to retrieve the PIN.

Revoke a device

To revoke a device, call revokeDevice:

<method name="revokeDevice" tp:name-for-bindings="revokeDevice">
    <tp:docstring>
        Revoke device attached to the given Jami account, and publish the new revocation list.
    </tp:docstring>
    <arg type="s" name="accountID" direction="in">
    </arg>
    <arg type="s" name="password" direction="in">
    </arg>
    <arg type="s" name="deviceId" direction="in">
    </arg>
    <arg type="b" name="success" direction="out">
        <tp:docstring>
            True if the operation was performed successfully.
        </tp:docstring>
    </arg>
</method>
<signal name="deviceRevocationEnded" tp:name-for-bindings="deviceRevocationEnded">
    <tp:docstring>
        Notify clients when the revokeDevice operation ended.
    </tp:docstring>
    <arg type="s" name="accountID">
    </arg>
    <arg type="s" name="deviceId">
    </arg>
    <arg type="i" name="status">
        <tp:docstring>
            Status code: 0 for success
            <ul>
                <li>SUCCESS = 0         everything went fine. Device is now revoked.</li>
                <li>WRONG_PASSWORD = 1  revocation failed: wrong password.</li>
                <li>UNKNOWN_DEVICE = 2  revocation failed: unknown device.</li>
            </ul>
        </tp:docstring>
    </arg>
</signal>

Upon completion, the deviceRevocationEnded signal is emitted with a status code:

  • 0 (SUCCESS)

  • 1 (WRONG_PASSWORD)

  • 2 (UNKNOWN_DEVICE)

Clients should handle this signal to confirm the revocation status.