summaryrefslogtreecommitdiffstats
path: root/services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs
diff options
context:
space:
mode:
Diffstat (limited to 'services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs')
-rw-r--r--services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs358
1 files changed, 358 insertions, 0 deletions
diff --git a/services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs b/services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs
new file mode 100644
index 0000000000..64f0e222bc
--- /dev/null
+++ b/services/fxaccounts/rust-bridge/firefox-accounts-bridge/src/bridge.rs
@@ -0,0 +1,358 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use crate::punt::{
+ error::{Error, Result},
+ PuntTask,
+};
+use fxa_client::FirefoxAccount;
+use nserror::{nsresult, NS_OK};
+use nsstring::{nsACString, nsCString};
+use once_cell::unsync::OnceCell;
+use std::{
+ str,
+ sync::{Arc, Mutex},
+};
+use storage_variant::HashPropertyBag;
+use thin_vec::ThinVec;
+use xpcom::{
+ interfaces::{mozIFirefoxAccountsBridgeCallback, nsIPropertyBag, nsISerialEventTarget},
+ RefPtr,
+};
+
+/// This macro calls `PuntTask::for_<fn_name>(fxa, <..args>, callback)`
+/// if `fxa` has been initialized.
+macro_rules! punt {
+ ($fn_name:ident $(, $arg:ident : $ty:ty)*) => {
+ fn $fn_name(&self $(, $arg: $ty)*, callback: &mozIFirefoxAccountsBridgeCallback) -> Result<()> {
+ if let Some(fxa) = self.fxa.get() {
+ let task_fn = paste::expr! { PuntTask::[<for_ $fn_name>] };
+ let task = task_fn(fxa $(, $arg)*, callback)?;
+ task.dispatch(&self.thread)?;
+ Ok(())
+ } else {
+ Err(Error::Unavailable)
+ }
+ }
+ }
+}
+
+/// An XPCOM binding for the Rust Firefox Accounts crate.
+#[derive(xpcom)]
+#[xpimplements(mozIFirefoxAccountsBridge)]
+#[refcnt = "nonatomic"] // Non-atomic because we have a `RefCell`.
+pub struct InitBridge {
+ // A background task queue used to run all our operations
+ // on a thread pool.
+ thread: RefPtr<nsISerialEventTarget>,
+ fxa: OnceCell<Arc<Mutex<FirefoxAccount>>>,
+}
+
+impl Bridge {
+ pub fn new() -> Result<RefPtr<Bridge>> {
+ let thread = moz_task::create_background_task_queue(cstr!("FirefoxAccountsBridge"))?;
+ Ok(Bridge::allocate(InitBridge {
+ thread,
+ fxa: OnceCell::new(),
+ }))
+ }
+
+ // This method (or InitFromJSON) must be called before any other one, because this
+ // is where we can finally give parameters for the Rust `FirefoxAccount` constructor
+ // and create an instance.
+ xpcom_method!(
+ init => Init(
+ options: *const nsIPropertyBag
+ )
+ );
+ fn init(&self, options: &nsIPropertyBag) -> Result<()> {
+ let options = HashPropertyBag::clone_from_bag(options)?;
+ let content_url: nsCString = options.get("content_url")?;
+ let content_url = str::from_utf8(&*content_url)?;
+ let client_id: nsCString = options.get("client_id")?;
+ let client_id = str::from_utf8(&*client_id)?;
+ let redirect_uri: nsCString = options.get("redirect_uri")?;
+ let redirect_uri = str::from_utf8(&*redirect_uri)?;
+ let token_server_url_override: nsCString = options.get("token_server_url_override")?;
+ let token_server_url_override = if token_server_url_override.is_empty() {
+ None
+ } else {
+ Some(str::from_utf8(&*token_server_url_override)?)
+ };
+ self.fxa
+ .set(Arc::new(Mutex::new(FirefoxAccount::new(
+ &content_url,
+ &client_id,
+ &redirect_uri,
+ token_server_url_override,
+ ))))
+ .map_err(|_| Error::AlreadyInitialized)?;
+ Ok(())
+ }
+
+ xpcom_method!(
+ from_json => InitFromJSON(
+ json: *const nsACString
+ )
+ );
+ fn from_json(&self, json: &nsACString) -> Result<()> {
+ let json = str::from_utf8(&*json)?;
+ self.fxa
+ .set(Arc::new(Mutex::new(FirefoxAccount::from_json(json)?)))
+ .map_err(|_| Error::AlreadyInitialized)?;
+ Ok(())
+ }
+
+ xpcom_method!(
+ to_json => StateJSON(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(to_json);
+
+ xpcom_method!(
+ begin_oauth_flow => BeginOAuthFlow(
+ scopes: *const ThinVec<nsCString>,
+ entry_point: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(
+ begin_oauth_flow,
+ scopes: &ThinVec<nsCString>,
+ entry_point: &nsACString
+ );
+
+ xpcom_method!(
+ complete_oauth_flow => CompleteOAuthFlow(
+ code: *const nsACString,
+ state: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(complete_oauth_flow, code: &nsACString, state: &nsACString);
+
+ xpcom_method!(
+ disconnect => Disconnect(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(disconnect);
+
+ xpcom_method!(
+ get_access_token => GetAccessToken(
+ scope: *const nsACString,
+ ttl: u64,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(get_access_token, scope: &nsACString, ttl: u64);
+
+ xpcom_method!(
+ get_session_token => GetSessionToken(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(get_session_token);
+
+ xpcom_method!(
+ get_attached_clients => GetAttachedClients(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(get_attached_clients);
+
+ xpcom_method!(
+ check_authorization_status => CheckAuthorizationStatus(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(check_authorization_status);
+
+ xpcom_method!(
+ clear_access_token_cache => ClearAccessTokenCache(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(clear_access_token_cache);
+
+ xpcom_method!(
+ handle_session_token_change => HandleSessionTokenChange(
+ session_token: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(handle_session_token_change, session_token: &nsACString);
+
+ xpcom_method!(
+ migrate_from_session_token => MigrateFromSessionToken(
+ session_token: *const nsACString,
+ k_sync: *const nsACString,
+ k_xcs: *const nsACString,
+ copy_session_token: bool,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(
+ migrate_from_session_token,
+ session_token: &nsACString,
+ k_sync: &nsACString,
+ k_xcs: &nsACString,
+ copy_session_token: bool
+ );
+
+ xpcom_method!(
+ retry_migrate_from_session_token => RetryMigrateFromSessionToken(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(retry_migrate_from_session_token);
+
+ xpcom_method!(
+ is_in_migration_state => IsInMigrationState(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(is_in_migration_state);
+
+ xpcom_method!(
+ get_profile => GetProfile(
+ ignore_cache: bool,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(get_profile, ignore_cache: bool);
+
+ xpcom_method!(
+ get_token_server_endpoint_url => GetTokenServerEndpointURL(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(get_token_server_endpoint_url);
+
+ xpcom_method!(
+ get_connection_success_url => GetConnectionSuccessURL(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(get_connection_success_url);
+
+ xpcom_method!(
+ get_manage_account_url => GetManageAccountURL(
+ entrypoint: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(get_manage_account_url, entrypoint: &nsACString);
+
+ xpcom_method!(
+ get_manage_devices_url => GetManageDevicesURL(
+ entrypoint: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(get_manage_devices_url, entrypoint: &nsACString);
+
+ xpcom_method!(
+ fetch_devices => FetchDevices(
+ ignore_cache: bool,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(fetch_devices, ignore_cache: bool);
+
+ xpcom_method!(
+ set_device_display_name => SetDeviceDisplayName(
+ name: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(set_device_display_name, name: &nsACString);
+
+ xpcom_method!(
+ handle_push_message => HandlePushMessage(
+ payload: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(handle_push_message, payload: &nsACString);
+
+ xpcom_method!(
+ poll_device_commands => PollDeviceCommands(
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(poll_device_commands);
+
+ xpcom_method!(
+ send_single_tab => SendSingleTab(
+ target_id: *const nsACString,
+ title: *const nsACString,
+ url: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+ punt!(
+ send_single_tab,
+ target_id: &nsACString,
+ title: &nsACString,
+ url: &nsACString
+ );
+
+ xpcom_method!(
+ set_device_push_subscription => SetDevicePushSubscription(
+ endpoint: *const nsACString,
+ public_key: *const nsACString,
+ auth_key: *const nsACString,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(
+ set_device_push_subscription,
+ endpoint: &nsACString,
+ public_key: &nsACString,
+ auth_key: &nsACString
+ );
+
+ xpcom_method!(
+ initialize_device => InitializeDevice(
+ name: *const nsACString,
+ device_type: *const nsACString,
+ supported_capabilities: *const ThinVec<nsCString>,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(
+ initialize_device,
+ name: &nsACString,
+ device_type: &nsACString,
+ supported_capabilities: &ThinVec<nsCString>
+ );
+
+ xpcom_method!(
+ ensure_capabilities => EnsureCapabilities(
+ supported_capabilities: *const ThinVec<nsCString>,
+ callback: *const mozIFirefoxAccountsBridgeCallback
+ )
+ );
+
+ punt!(
+ ensure_capabilities,
+ supported_capabilities: &ThinVec<nsCString>
+ );
+}