Open4

RustのTIPS

青柳康平青柳康平

スレッドの中で乱数を使う。

rand = "0.8.5"
use rand::{Rng, SeedableRng};
let mut rng = rand::rngs::StdRng::from_entropy();
let res = rng.gen::<u8>();
青柳康平青柳康平

minioを使ってS3にアクセス

let credentials_provider = Credentials::new("admin123", "admin123", None, None, "example");
let config = aws_sdk_s3::Config::builder()
    .behavior_version_latest()
    .credentials_provider(credentials_provider)
    .region(Region::new("ap-northeast-1"))
    .force_path_style(true)
    .endpoint_url("http://minio:9000")
    .build();
Client::from_conf(config);
青柳康平青柳康平

AESとCTRのサンプル

main.rs
use aes::cipher::StreamCipher;
use ctr::cipher::KeyIvInit;
type Aes128Ctr64LE = ctr::Ctr64LE<aes::Aes128>;

// 暗号化
fn encrypt(key: &str, data: &str) -> Vec<u8> {
    use rand::{Rng, SeedableRng};
    let mut rng = rand::rngs::StdRng::from_entropy();
    let iv = rng.gen::<[u8; 16]>();
    let mut cipher = Aes128Ctr64LE::new(key.as_bytes().into(), &iv.into());
    let mut buf = data.as_bytes().to_vec();
    cipher.apply_keystream(&mut buf);
    let mut res = iv.to_vec();
    res.extend(buf);
    res
}

// 復号化
fn decrypt(key: &str, data: &Vec<u8>) -> String {
    let mut cipher = Aes128Ctr64LE::new(key.as_bytes().into(), data[0..16].into());
    let mut buf2: Vec<u8> = vec![0; data.len() - 16];
    if let Err(err) = cipher.apply_keystream_b2b(&data[16..], &mut buf2.as_mut_slice()) {
        println!("{}", err);
    }
    String::from_utf8(buf2.to_vec()).unwrap()
}

fn main() {
    let plaintext = "予定表~①💖ハンカクだ";
    let key = "0123456701234567";
    let enc = encrypt(key, plaintext);
    let dec = decrypt(key, &enc);
    assert_eq!(plaintext, dec);
    println!("{}", dec);
}
青柳康平青柳康平

CloudflareでOAuth2

Cargo.toml
[package]
name = "cms"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
axum  = { version = "0.7", default-features = false, features = ['query', 'json'] }
console_error_panic_hook = { version = "0.1.1" }
tower-cookies = "0.10.0"
tower-service = "0.3.2"
twapi-v2 = { version = "0.14", features = ["rustls-tls", "oauth"], default-features = false }
worker = { version = "0.1.0", features=['http', 'axum'] }
worker-macros = { version = "0.1.0", features = ['http'] }


[profile.release]
opt-level = "s" # optimize for size in release builds
lto = true
strip = true
codegen-units = 1
lib.rs
use std::{collections::HashMap, sync::Arc};

use axum::{extract::{Query, State}, response::{Html, IntoResponse, Json}, routing::get, Router};
use tower_cookies::{Cookie, CookieManagerLayer, Cookies};
use tower_service::Service;
use twapi_v2::{api::{get_2_users_me, BearerAuthentication}, oauth::{TwitterOauth, TwitterScope}};
use worker::*;

pub const PKCE_VERIFIER: &str = "pkce_verifier";

pub struct AppState {
    pub twitter_oauth: TwitterOauth,
}

fn router(env: &Env) -> Router {
    let twitter_oauth = oauth_client(&env).unwrap();
    let app_store = Arc::new(AppState { twitter_oauth });
    Router::new()
        .route("/", get(root))
        .route("/oauth", get(oauth))
        .with_state(app_store)
        .layer(CookieManagerLayer::new())
}

#[event(fetch)]
async fn fetch(
    req: HttpRequest,
    env: Env,
    _ctx: Context,
) -> Result<axum::http::Response<axum::body::Body>> {
    console_error_panic_hook::set_once();
    Ok(router(&env).call(req).await?)
}

fn oauth_client(env: &Env) -> Result<TwitterOauth> {
    TwitterOauth::new(
        &env.secret("CLIENT_ID").unwrap().to_string(),
        &env.secret("CLIENT_SECRET").unwrap().to_string(),
        &env.var("CALLBACK_URL").unwrap().to_string(),
        TwitterScope::all(),
    ).map_err(|e| Error::RustError(e.to_string()))
}

pub async fn root(cookies: Cookies, State(state): State<Arc<AppState>>,) -> impl IntoResponse {
    let res = state.twitter_oauth.oauth_url();
    cookies.add(Cookie::new(PKCE_VERIFIER, res.pkce_verifier.clone()));
    Html(format!("<a href='{}'>oauth<a>", res.oauth_url)).into_response()
}

#[worker::send]
async fn oauth(cookies: Cookies, State(state): State<Arc<AppState>>, Query(params): Query<HashMap<String, String>>, ) -> impl IntoResponse {
    let pkce = cookies.get(PKCE_VERIFIER).unwrap();
    let code  = params.get("code").unwrap();
    let res = state.twitter_oauth
        .token(pkce.value(), code)
        .await
        .unwrap();
    println!("{:?}", res);
    let auth = BearerAuthentication::new(res.access_token);
    let me = get_2_users_me::Api::all().execute(&auth).await.unwrap();
    Json(me.0).into_response()
}