examples_fxa_client/
main.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5mod devices;
6mod send_tab;
7
8use std::fs;
9
10use clap::{Parser, Subcommand, ValueEnum};
11use cli_support::fxa_creds;
12use fxa_client::{FirefoxAccount, FxaConfig, FxaServer};
13
14static CREDENTIALS_FILENAME: &str = "credentials.json";
15static CLIENT_ID: &str = "a2270f727f45f648";
16static REDIRECT_URI: &str = "https://accounts.firefox.com/oauth/success/a2270f727f45f648";
17
18use anyhow::Result;
19
20#[derive(Parser)]
21#[command(about, long_about = None)]
22struct Cli {
23    /// The FxA server to use
24    #[arg(value_enum, default_value_t = Server::Release)]
25    server: Server,
26
27    /// Request a session scope
28    #[clap(long, short, action)]
29    session_scope: bool,
30
31    /// Print out log to the console.  The default level is WARN
32    #[clap(long, short, action)]
33    log: bool,
34
35    /// Set the logging level to INFO
36    #[clap(long, short, action)]
37    info: bool,
38
39    /// Set the logging level to DEBUG
40    #[clap(long, short, action)]
41    debug: bool,
42
43    #[command(subcommand)]
44    command: Command,
45}
46
47#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
48enum Server {
49    /// Official server
50    Release,
51    /// China server
52    China,
53    /// stable dev sever
54    Stable,
55    /// staging dev sever
56    Stage,
57    /// local dev sever
58    LocalDev,
59}
60
61#[derive(Subcommand)]
62enum Command {
63    Devices(devices::DeviceArgs),
64    SendTab(send_tab::SendTabArgs),
65    Disconnect,
66}
67
68fn main() -> Result<()> {
69    let cli = Cli::parse();
70    viaduct_reqwest::use_reqwest_backend();
71    if cli.log {
72        if cli.debug {
73            simple_logger::init_with_level(log::Level::Debug).unwrap();
74        } else if cli.info {
75            simple_logger::init_with_level(log::Level::Info).unwrap();
76        } else {
77            simple_logger::init_with_level(log::Level::Warn).unwrap();
78        }
79    }
80
81    let scopes: &[&str] = if cli.session_scope {
82        &[fxa_creds::SYNC_SCOPE, fxa_creds::SESSION_SCOPE]
83    } else {
84        &[fxa_creds::SYNC_SCOPE]
85    };
86
87    println!();
88    let account = load_account(&cli, scopes)?;
89    match cli.command {
90        Command::Devices(args) => devices::run(&account, args),
91        Command::SendTab(args) => send_tab::run(&account, args),
92        Command::Disconnect => {
93            account.disconnect();
94            Ok(())
95        }
96    }?;
97
98    Ok(())
99}
100
101fn load_account(cli: &Cli, scopes: &[&str]) -> Result<FirefoxAccount> {
102    let config = FxaConfig {
103        server: match cli.server {
104            Server::Release => FxaServer::Release,
105            Server::Stable => FxaServer::Stable,
106            Server::Stage => FxaServer::Stage,
107            Server::China => FxaServer::China,
108            Server::LocalDev => FxaServer::LocalDev,
109        },
110        redirect_uri: REDIRECT_URI.into(),
111        client_id: CLIENT_ID.into(),
112        token_server_url_override: None,
113    };
114    fxa_creds::get_cli_fxa(config, &credentials_path(), scopes).map(|cli| cli.account)
115}
116
117pub fn persist_fxa_state(acct: &FirefoxAccount) -> Result<()> {
118    let json = acct.to_json().unwrap();
119    Ok(fs::write(credentials_path(), json)?)
120}
121
122fn credentials_path() -> String {
123    cli_support::cli_data_path(CREDENTIALS_FILENAME)
124}