Skip to content

Commit

Permalink
0.14.1: Add fie auth command
Browse files Browse the repository at this point in the history
This command will allow user to authorize with twitter using PIN based token
  • Loading branch information
DoumanAsh committed Jun 15, 2019
1 parent 31d8726 commit 3de6101
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fie"
version = "0.14.0"
version = "0.14.1"
authors = ["Douman <douman@gmx.se>"]
repository = "https://github.com/DoumanAsh/fie"
description = "Small and cute social media utility."
Expand Down
47 changes: 38 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@
[![Build status](https://ci.appveyor.com/api/projects/status/oc937oppd38x1y4y/branch/master?svg=true)](https://ci.appveyor.com/project/DoumanAsh/fie/branch/master)
[![Build Status](https://travis-ci.org/DoumanAsh/fie.svg?branch=master)](https://travis-ci.org/DoumanAsh/fie)
[![Crates.io](https://img.shields.io/crates/v/fie.svg)](https://crates.io/crates/fie)
[![Dependency status](https://deps.rs/crate/fie/0.14.0/status.svg)](https://deps.rs/crate/fie)
[![Dependency status](https://deps.rs/crate/fie/0.14.1/status.svg)](https://deps.rs/crate/fie)

Small and cute social media CLI.

![Icon](icon.jpg)

## Download links
## Installation

* Windows [32bit](https://github.com/DoumanAsh/fie/releases/download/0.14.0/fie-0.14.0-i686-pc-windows-msvc.zip)
* Windows [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.0/fie-0.14.0-x86_64-pc-windows-msvc.zip)
* Linux [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.0/fie-0.14.0-x86_64-unknown-linux-gnu.zip)
* OSX [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.0/fie-0.14.0-x86_64-apple-darwin.zip)
### Download links

* Windows [32bit](https://github.com/DoumanAsh/fie/releases/download/0.14.1/fie-0.14.1-i686-pc-windows-msvc.zip)
* Windows [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.1/fie-0.14.1-x86_64-pc-windows-msvc.zip)
* Linux [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.1/fie-0.14.1-x86_64-unknown-linux-gnu.zip)
* OSX [64bit](https://github.com/DoumanAsh/fie/releases/download/0.14.1/fie-0.14.1-x86_64-apple-darwin.zip)

### Cargo

In order to install CLI utility you need to enable feature `cli`
In addition to that following environment variables are used optionally:

- Twitter Consumer Token (requires both to present for it to be used):
- `FIE_TWITTER_CONSUMER_KEY` - Builtin Consumer key for twitter API;
- `FIE_TWITTER_CONSUMER_SECRET` - Builtin Consumer secret for twitter API;

## Supported social platforms:

Expand Down Expand Up @@ -48,6 +59,7 @@ FLAGS:
-V, --version Prints version information
SUBCOMMANDS:
auth Allows to perform authorization with social media.
batch Load CLI arguments from file and runs it.
env Prints information about app environment.
help Prints this message or the help of the given subcommand(s)
Expand Down Expand Up @@ -79,9 +91,9 @@ ARGS:

### batch

```
Load CLI arguments from file and runs it.

```
USAGE:
fie.exe batch <file>
Expand All @@ -100,8 +112,6 @@ File examples:
Prints information about app's environment.

```
Prints information about app environment.
USAGE:
fie.exe env <SUBCOMMAND>
Expand All @@ -112,3 +122,22 @@ SUBCOMMANDS:
config Prints path to config file.
help Prints this message or the help of the given subcommand(s)
```

### auth

Allows to perform user authorization using social media API.
Currently available authorizations:

- Twitter PIN based auth. Interactive dialogue will prompt you to follow link and authorize fie.

```
USAGE:
fie.exe auth <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
SUBCOMMANDS:
help Prints this message or the help of the given subcommand(s)
twitter Performs authorization with twitter
```
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ environment:
global:
PROJECT_NAME: fie
matrix:
- TARGET: i686-pc-windows-msvc
CHANNEL: stable
- TARGET: x86_64-pc-windows-msvc
CHANNEL: stable
- TARGET: i686-pc-windows-msvc
CHANNEL: stable

# Install Rust and Cargo
# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
Expand Down
32 changes: 25 additions & 7 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,6 @@ password = "password"

## Twitter

Go to [app page](https://apps.twitter.com/) and create new app for yourself.

After that go to section `Keys and Access Tokens` to retrieve configuration:

`Application Settings` has `Consumer Key` and `Consumer Secret`
Put it in section below:

```toml
[api.twitter.consumer]
key = "key"
Expand All @@ -54,6 +47,31 @@ key = "token"
secret = "secret"
```

### Using own application

Go to [app page](https://apps.twitter.com/) and create new app for yourself.

After that go to section `Keys and Access Tokens` to retrieve configuration:

`Application Settings` has `Consumer Key` and `Consumer Secret`
Put it in section below:

### Using fie builtin tokens

In this case fie must have been built with following environment variables:

- `FIE_TWITTER_CONSUMER_KEY` - contains consumer key of application.
- `FIE_TWITTER_CONSUMER_SECRET` - contains consumer secret of application.

Provided download links will contain `fie` own consumer token.
Therefore `api.twitter.consumer` can be omitted

In this case you can use command `fie auth twitter` in order to get `api.twitter.access`
After successfully following interactive instructions, the `api.twitter.access` configuration will be printed in stdout.
This should replace whatever you already have in your configuration.

Use `fie env config` to find configuration file location.

## Mastodon

You need to provide host name of the Mastodon instance.
Expand Down
5 changes: 3 additions & 2 deletions fie.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ username = "username"
password = "password"

# Consumer Token of twitter app
# This can be omitted to use builtin consumer token with authorization command
[api.twitter.consumer]
key = "key"
secret = "secret"
key = ""
secret = ""

# Authorization Token to access user account. Generated in developer page.
[api.twitter.access]
Expand Down
140 changes: 140 additions & 0 deletions src/cli/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use fie::config;
use fie::api;
use fie::api::http::{self, AutoClient, AutoRuntime, Request};
use serde_derive::{Deserialize};

use std::io::{self, Write};
use std::collections::HashMap;

pub fn twitter(mut config: config::Twitter) {
const REQUEST_TOKEN_URI: &str = "https://api.twitter.com/oauth/request_token";
const ACCESS_TOKEN_URI: &str = "https://api.twitter.com/oauth/access_token";

#[derive(Deserialize, Debug)]
struct RequestTokenRsp {
oauth_token: String,
oauth_token_secret: String,
}

config.access.key.truncate(0);
config.access.secret.truncate(0);

let mut oauth = api::twitter::data::Oauth::new(config);

let _http = http::init(&Default::default());

let (auth_params, auth_header) = {
let mut auth_params = HashMap::new();
auth_params.insert("oauth_callback", "oob");
auth_params.insert("x_auth_access_type", "write");
(auth_params.clone(), oauth.gen_auth(&http::Method::POST, REQUEST_TOKEN_URI, auth_params))
};

let req = Request::post(REQUEST_TOKEN_URI).expect("To create request")
.set_header(http::header::AUTHORIZATION, auth_header)
.form(&auth_params)
.expect("To serialize form params")
.send()
.finish();

let request_token: RequestTokenRsp = match req {
Ok(response) => match response.is_success() {
true => match response.text().finish() {
Ok(response) => match yukikaze::serde_urlencoded::from_str(&response) {
Ok(response) => response,
Err(error) => {
eprintln!("Unable to parse response with request token. Error: {}", error);
return;
}
},
Err(error) => {
eprintln!("Failed to read response with requested token. Error: {}", error);
return;
}
},
false => {
eprintln!("Request for token failed with {}", response.status());
return;
}
},
Err(error) => {
eprintln!("Failed to request ouath token :( Error: {}", error);
return;
}
};

println!("Please use following link to authroize fie:\nhttps://api.twitter.com/oauth/authorize?oauth_token={}", request_token.oauth_token);
println!("Once done please enter PIN...");
let pin = {
let mut buffer = String::new();
let stdin = io::stdin();
let stdout = io::stdout();
let mut stdout = stdout.lock();

loop {
buffer.truncate(0);

let _ = stdout.write_all(b"Print: ");
let _ = stdout.flush();
match stdin.read_line(&mut buffer) {
Ok(_) => (),
Err(_) => {
let _ = stdout.write_all(b"Failed to read input. Try again...\n");
continue;
}
}

let pin = buffer.trim();
match pin.parse::<u32>() {
Ok(_) => break pin.to_owned(),
Err(_) => {
let _ = stdout.write_all(b"Invalid PIN specified, should contain only digits. Try again...\n");
continue;
}
}
}
};

oauth.set_oauth_token(&request_token.oauth_token);
let (auth_params, auth_header) = {
let mut auth_params = HashMap::new();
auth_params.insert("oauth_verifier", pin.trim());
(auth_params.clone(), oauth.gen_auth(&http::Method::POST, ACCESS_TOKEN_URI, auth_params))
};

let req = Request::post(ACCESS_TOKEN_URI).expect("To create request")
.set_header(http::header::AUTHORIZATION, auth_header)
.form(&auth_params)
.expect("To serialize form params")
.send()
.finish();

let access_token: RequestTokenRsp = match req {
Ok(response) => match response.is_success() {
true => match response.text().finish() {
Ok(response) => match yukikaze::serde_urlencoded::from_str(&response) {
Ok(response) => response,
Err(error) => {
eprintln!("Unable to parse response with access token. Error: {}", error);
return;
}
},
Err(error) => {
eprintln!("Failed to read response with access token. Error: {}", error);
return;
}
},
false => {
eprintln!("Request for access token failed with {}", response.status());
return;
}
},
Err(error) => {
eprintln!("Failed to request access token :( Error: {}", error);
return;
}
};

println!("Received access token successfully.\nAdd following to your fie configuration file:");
println!("[api.twitter.access]\nkey = \"{}\"\nsecret = \"{}\"", access_token.oauth_token, access_token.oauth_token_secret);
}
10 changes: 10 additions & 0 deletions src/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ pub enum Command {
#[structopt(name = "batch")]
///Load CLI arguments from file and runs it.
Batch(Batch),
#[structopt(name = "auth")]
///Allows to perform authorization with social media.
Auth(Auth),
}

#[derive(Debug, StructOpt)]
Expand Down Expand Up @@ -98,3 +101,10 @@ pub enum Env {
///Prints path to config file.
Config,
}

#[derive(Debug, StructOpt)]
pub enum Auth {
#[structopt(name = "twitter")]
///Performs authorization with twitter
Twitter,
}
25 changes: 25 additions & 0 deletions src/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde_derive::Deserialize;

mod config;
mod cli;
mod auth;

use fie::config::Config;
use config::FileSystemLoad;
Expand Down Expand Up @@ -78,8 +79,27 @@ fn open_batch(path: &str) -> io::Result<Batch> {
config::load_from_file(Path::new(path))
}

fn use_twitter_builtin_consumer(twitter: &mut fie::config::Twitter) {
const CONSUMER_KEY: Option<&'static str> = option_env!("FIE_TWITTER_CONSUMER_KEY");
const CONSUMER_SECRET: Option<&'static str> = option_env!("FIE_TWITTER_CONSUMER_SECRET");

//Only set if either part of consumer token is missing
match (CONSUMER_KEY, CONSUMER_SECRET) {
(Some(key), Some(secret)) => if twitter.consumer.key.len() == 0 || twitter.consumer.secret.len() == 0{
twitter.consumer.key.truncate(0);
twitter.consumer.secret.truncate(0);

twitter.consumer.key.push_str(key);
twitter.consumer.secret.push_str(secret);
},
_ => (),
}
}

fn run() -> io::Result<()> {
let mut config = Config::load()?;
use_twitter_builtin_consumer(&mut config.api.twitter);

let args = cli::Args::new(&mut config.platforms);

match args.cmd {
Expand All @@ -100,6 +120,11 @@ fn run() -> io::Result<()> {
},
cli::Command::Env(env) => match env {
cli::Env::Config => println!("{}", Config::path()?.display())
},
cli::Command::Auth(typ) => match typ {
cli::Auth::Twitter => {
auth::twitter(config.api.twitter);
}
}
}

Expand Down
Loading

0 comments on commit 3de6101

Please sign in to comment.