1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::{
    commands::AsyncCliCommand,
    config::{WasmerConfig, WasmerEnv, DEFAULT_PROD_REGISTRY},
};
use colored::Colorize;
use is_terminal::IsTerminal;

/// Subcommand for log in a user into Wasmer (using a browser or provided a token)
#[derive(Debug, Clone, clap::Parser)]
pub struct Logout {
    #[clap(flatten)]
    env: WasmerEnv,

    /// Do not prompt for user input.
    #[clap(long, default_value_t = !std::io::stdin().is_terminal())]
    pub non_interactive: bool,

    /// Whether or not to revoke the associated token
    #[clap(long)]
    pub revoke_token: bool,
}

#[async_trait::async_trait]
impl AsyncCliCommand for Logout {
    type Output = ();

    async fn run_async(self) -> Result<Self::Output, anyhow::Error> {
        let registry = self.env.registry_endpoint()?.to_string();
        let host_str = self
            .env
            .registry_public_url()
            .map_err(|_| anyhow::anyhow!("No registry not specified!"))?
            .host_str()
            .unwrap()
            .bold();

        let client = self
            .env
            .client()
            .map_err(|_| anyhow::anyhow!("Not logged into registry {host_str}"))?;

        let user = wasmer_backend_api::query::current_user(&client)
            .await
            .map_err(|e| anyhow::anyhow!("Not logged into registry {host_str}: {e}"))?
            .ok_or_else(|| anyhow::anyhow!("Not logged into registry {host_str}"))?;

        let theme = dialoguer::theme::ColorfulTheme::default();
        let prompt = dialoguer::Confirm::with_theme(&theme).with_prompt(format!(
            "Log user {} out of registry {host_str}?",
            user.username
        ));

        if prompt.interact()? || self.non_interactive {
            let mut config = self.env.config()?;
            let token = config
                .registry
                .get_login_token_for_registry(&registry)
                .unwrap();
            config.registry.remove_registry(&registry);
            if config.registry.is_current_registry(&registry) {
                if config.registry.tokens.is_empty() {
                    _ = config
                        .registry
                        .set_current_registry(DEFAULT_PROD_REGISTRY)
                        .await;
                } else {
                    let new_reg = config.registry.tokens[0].registry.clone();
                    _ = config.registry.set_current_registry(&new_reg).await;
                }
            }
            let path = WasmerConfig::get_file_location(self.env.dir());
            config.save(path)?;

            // Read it again..
            //
            let config = self.env.config()?;
            if config
                .registry
                .get_login_token_for_registry(&registry)
                .is_none()
            {
                println!(
                    "User {} correctly logged out of registry {host_str}",
                    user.username.bold()
                );

                let should_revoke = self.revoke_token || {
                    let theme = dialoguer::theme::ColorfulTheme::default();
                    dialoguer::Confirm::with_theme(&theme)
                        .with_prompt("Revoke token?")
                        .interact()?
                };

                if should_revoke {
                    wasmer_backend_api::query::revoke_token(&client, token).await?;
                    println!(
                        "Token for user {} in registry {host_str} correctly revoked",
                        user.username.bold()
                    );
                }
            } else {
                anyhow::bail!("Something went wrong! User is not logged out.")
            }
        } else {
            println!("No action taken.");
        }

        Ok(())
    }
}