Rename Question to Message

This commit is contained in:
Kenny Levinsen
2020-01-28 21:43:36 +01:00
parent 30411ae50f
commit 07b0e3328d
9 changed files with 82 additions and 77 deletions

10
Cargo.lock generated
View File

@@ -2,10 +2,10 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "agreety" name = "agreety"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"greet_proto 0.2.0", "greet_proto 0.3.0",
"nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-ini 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "rust-ini 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -162,7 +162,7 @@ dependencies = [
[[package]] [[package]]
name = "greet_proto" name = "greet_proto"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -174,12 +174,12 @@ dependencies = [
[[package]] [[package]]
name = "greetd" name = "greetd"
version = "0.1.1" version = "0.2.0"
dependencies = [ dependencies = [
"async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "async-trait 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"greet_proto 0.2.0", "greet_proto 0.3.0",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pam-sys 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "pam-sys 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -56,13 +56,13 @@ The greeter runs as a configured user, which is supposed to be one with no inter
# Protocol # Protocol
``` ```
________________________________________________________ _______________________________
| | | | | | | |
| magic u32 | version u32 | payload_length u32 | payload | | payload_length u32 | payload |
|___________|_____________|____________________|_________| |____________________|_________|
``` ```
Magic is always `0xAFBFCFDF`, version is `1`, payload is JSON. `payload_length` is native endianness, payload is JSON.
Requests and responses are encoded the same. Requests and responses are encoded the same.
@@ -79,14 +79,14 @@ Create a new session for the given user. This may result in authentication quest
} }
``` ```
### AnswerAuthQuestion ### PostAuthMessageResponse
Answer an authentication question. Answer an authentication question.
``` ```
{ {
"type": "answer_auth_question", "type": "post_auth_message_response",
"answer": "password" "response": "password"
} }
``` ```
@@ -140,14 +140,14 @@ The action failed.
``` ```
### AuthQuestion ### AuthMessage
The action resulted in authentication questions. The action resulted in authentication questions.
``` ```
{ {
"type": "auth_question", "type": "auth_message",
"question": "Password: ", "message": "Password: ",
"style": "secret" "message_type": "secret"
} }
``` ```

View File

@@ -9,7 +9,7 @@ use ini::Ini;
use nix::sys::utsname::uname; use nix::sys::utsname::uname;
use rpassword::prompt_password_stderr; use rpassword::prompt_password_stderr;
use greet_proto::{codec::SyncCodec, ErrorType, QuestionStyle, Request, Response}; use greet_proto::{codec::SyncCodec, AuthMessageType, ErrorType, Request, Response};
fn prompt_stderr(prompt: &str) -> Result<String, Box<dyn std::error::Error>> { fn prompt_stderr(prompt: &str) -> Result<String, Box<dyn std::error::Error>> {
let stdin = io::stdin(); let stdin = io::stdin();
@@ -65,22 +65,25 @@ fn login(node: &str, cmd: &Option<String>) -> Result<LoginResult, Box<dyn std::e
next_request.write_to(&mut stream)?; next_request.write_to(&mut stream)?;
match Response::read_from(&mut stream)? { match Response::read_from(&mut stream)? {
Response::AuthQuestion { question, style } => { Response::AuthMessage {
let answer = match style { auth_message,
QuestionStyle::Visible => prompt_stderr(&question)?, auth_message_type,
QuestionStyle::Secret => prompt_password_stderr(&question)?, } => {
QuestionStyle::Info => { let answer = match auth_message_type {
eprintln!("info: {}", question); AuthMessageType::Visible => prompt_stderr(&auth_message)?,
AuthMessageType::Secret => prompt_password_stderr(&auth_message)?,
AuthMessageType::Info => {
eprintln!("info: {}", auth_message);
"".to_string() "".to_string()
} }
QuestionStyle::Error => { AuthMessageType::Error => {
eprintln!("error: {}", question); eprintln!("error: {}", auth_message);
"".to_string() "".to_string()
} }
}; };
next_request = Request::AnswerAuthQuestion { next_request = Request::PostAuthMessageResponse {
answer: Some(answer), response: Some(answer),
}; };
} }
Response::Success => { Response::Success => {

View File

@@ -46,28 +46,28 @@ use serde::{Deserialize, Serialize};
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Request { pub enum Request {
/// CreateSession initiates a login attempt for the given user. /// CreateSession initiates a login attempt for the given user.
/// CreateSession returns either a Response::AuthQuestion, /// CreateSession returns either a Response::AuthMessage,
/// Response::Success or Response::Failure. /// Response::Success or Response::Failure.
/// ///
/// If a question is returned, it should be answered with a /// If an auth message is returned, it should be answered with a
/// Request::AnswerAuthQuestion. If a success is returned, the session can /// Request::PostAuthMessageResponse. If a success is returned, the session
/// then be started with Request::StartSession. /// can then be started with Request::StartSession.
/// ///
/// If a login flow needs to be aborted at any point, send /// If a login flow needs to be aborted at any point, send
/// Request::CancelSession. Note that the session is cancelled /// Request::CancelSession. Note that the session is cancelled
/// automatically on error. /// automatically on error.
CreateSession { username: String }, CreateSession { username: String },
/// AnswerAuthQuestion answers the last auth question, and returns either /// PostAuthMessageResponse responds to the last auth message, and returns
/// a Response::AuthQuestion, Response::Success or Response::Failure. /// either a Response::AuthMessage, Response::Success or Response::Failure.
/// ///
/// If a question is returned, it should be answered with a /// If an auth message is returned, it should be answered with a
/// Request::AnswerAuthQuestion. If a success is returned, the session can /// Request::PostAuthMessageResponse. If a success is returned, the session
/// then be started with Request::StartSession. /// can then be started with Request::StartSession.
AnswerAuthQuestion { answer: Option<String> }, PostAuthMessageResponse { response: Option<String> },
/// Start a successfully logged in session. This will fail if the session /// Start a successfully logged in session. This will fail if the session
/// has pending questions or has encountered an error. /// has pending messages or has encountered an error.
StartSession { cmd: Vec<String>, env: Vec<String> }, StartSession { cmd: Vec<String>, env: Vec<String> },
/// Cancel a session. This can only be done if the session has not been /// Cancel a session. This can only be done if the session has not been
@@ -87,10 +87,10 @@ pub enum ErrorType {
AuthError, AuthError,
} }
/// A question style for a Response::AuthQuestion. Serialized as snake_case. /// A message type for a Response::AuthMessage. Serialized as snake_case.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum QuestionStyle { pub enum AuthMessageType {
/// A question whose answer should be visible during input. /// A question whose answer should be visible during input.
Visible, Visible,
@@ -111,9 +111,9 @@ pub enum QuestionStyle {
/// ///
/// ```json /// ```json
/// { /// {
/// "type": "auth_question", /// "type": "auth_message",
/// "question": "Password:", /// "message": "Password:",
/// "style": "secret" /// "message_type": "secret"
/// } /// }
/// ``` /// ```
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@@ -130,18 +130,18 @@ pub enum Response {
description: String, description: String,
}, },
/// An authentication question needs to be answered to continue through the /// An authentication message needs to be answered to continue through the
/// authentication flow. /// authentication flow.
/// ///
/// An authentication question can consist of anything. While it will /// An authentication message can consist of anything. While it will
/// commonly just be a request for the users' password, it could also ask /// commonly just be a request for the users' password, it could also ask
/// for TOTP codes, or whether or not you felt sad when Littlefoot's mother /// for TOTP codes, or whether or not you felt sad when Littlefoot's mother
/// died in the original "Land Before Time". It is therefore important that /// died in the original "Land Before Time". It is therefore important that
/// no assumptions are made about the questions that will be asked, and /// no assumptions are made about the questions that will be asked, and
/// attempts to automatically answer these questions should not be made. /// attempts to automatically answer these questions should not be made.
AuthQuestion { AuthMessage {
style: QuestionStyle, auth_message_type: AuthMessageType,
question: String, auth_message: String,
}, },
} }

View File

@@ -10,10 +10,10 @@ use crate::{
error::Error, error::Error,
session::{ session::{
interface::{Session, SessionChild, SessionState}, interface::{Session, SessionChild, SessionState},
worker::QuestionStyle as SessQuestionStyle, worker::AuthMessageType as SessAuthMessageType,
}, },
}; };
use greet_proto::QuestionStyle; use greet_proto::AuthMessageType;
struct SessionChildSet { struct SessionChildSet {
child: SessionChild, child: SessionChild,
@@ -139,17 +139,17 @@ impl Context {
} }
/// Retrieve a question from the session under configuration. /// Retrieve a question from the session under configuration.
pub async fn get_question(&self) -> Result<Option<(QuestionStyle, String)>, Error> { pub async fn get_question(&self) -> Result<Option<(AuthMessageType, String)>, Error> {
let mut inner = self.inner.write().await; let mut inner = self.inner.write().await;
match &mut inner.configuring { match &mut inner.configuring {
Some(s) => match s.session.get_state().await? { Some(s) => match s.session.get_state().await? {
SessionState::Ready => Ok(None), SessionState::Ready => Ok(None),
SessionState::Question(style, string) => Ok(Some(( SessionState::Question(style, string) => Ok(Some((
match style { match style {
SessQuestionStyle::Visible => QuestionStyle::Visible, SessAuthMessageType::Visible => AuthMessageType::Visible,
SessQuestionStyle::Secret => QuestionStyle::Secret, SessAuthMessageType::Secret => AuthMessageType::Secret,
SessQuestionStyle::Info => QuestionStyle::Info, SessAuthMessageType::Info => AuthMessageType::Info,
SessQuestionStyle::Error => QuestionStyle::Error, SessAuthMessageType::Error => AuthMessageType::Error,
}, },
string, string,
))), ))),
@@ -159,10 +159,10 @@ impl Context {
} }
/// Answer a question to the session under configuration. /// Answer a question to the session under configuration.
pub async fn post_answer(&self, answer: Option<String>) -> Result<(), Error> { pub async fn post_response(&self, answer: Option<String>) -> Result<(), Error> {
let mut inner = self.inner.write().await; let mut inner = self.inner.write().await;
match &mut inner.configuring { match &mut inner.configuring {
Some(s) => s.session.post_answer(answer).await, Some(s) => s.session.post_response(answer).await,
None => Err("no session under configuration".into()), None => Err("no session under configuration".into()),
} }
} }

View File

@@ -42,9 +42,9 @@ fn wrap_result<T>(res: Result<T, Error>) -> Response {
async fn client_get_question(ctx: &Context) -> Response { async fn client_get_question(ctx: &Context) -> Response {
match ctx.get_question().await { match ctx.get_question().await {
Ok(Some((style, msg))) => Response::AuthQuestion { Ok(Some((auth_message_type, auth_message))) => Response::AuthMessage {
style, auth_message_type,
question: msg, auth_message,
}, },
res => wrap_result(res), res => wrap_result(res),
} }
@@ -63,10 +63,12 @@ async fn client_handler(ctx: Rc<Context>, mut s: UnixStream) -> Result<(), Error
Ok(()) => client_get_question(&ctx).await, Ok(()) => client_get_question(&ctx).await,
res => wrap_result(res), res => wrap_result(res),
}, },
Request::AnswerAuthQuestion { answer } => match ctx.post_answer(answer).await { Request::PostAuthMessageResponse { response } => {
Ok(()) => client_get_question(&ctx).await, match ctx.post_response(response).await {
res => wrap_result(res), Ok(()) => client_get_question(&ctx).await,
}, res => wrap_result(res),
}
}
Request::StartSession { cmd, env } => wrap_result(ctx.start(cmd, env).await), Request::StartSession { cmd, env } => wrap_result(ctx.start(cmd, env).await),
Request::CancelSession => wrap_result(ctx.cancel().await), Request::CancelSession => wrap_result(ctx.cancel().await),
}; };

View File

@@ -1,4 +1,4 @@
use super::worker::{ParentToSessionChild, QuestionStyle, SessionChildToParent}; use super::worker::{AuthMessageType, ParentToSessionChild, SessionChildToParent};
use crate::pam::converse::Converse; use crate::pam::converse::Converse;
/// SessionConv is a PAM conversation implementation that forwards questions /// SessionConv is a PAM conversation implementation that forwards questions
@@ -8,7 +8,7 @@ pub struct SessionConv<'a> {
} }
impl<'a> SessionConv<'a> { impl<'a> SessionConv<'a> {
fn question(&self, msg: &str, style: QuestionStyle) -> Result<String, ()> { fn question(&self, msg: &str, style: AuthMessageType) -> Result<String, ()> {
let msg = SessionChildToParent::PamMessage { let msg = SessionChildToParent::PamMessage {
style, style,
msg: msg.to_string(), msg: msg.to_string(),
@@ -34,15 +34,15 @@ impl<'a> SessionConv<'a> {
impl<'a> Converse for SessionConv<'a> { impl<'a> Converse for SessionConv<'a> {
fn prompt_echo(&self, msg: &str) -> Result<String, ()> { fn prompt_echo(&self, msg: &str) -> Result<String, ()> {
self.question(msg, QuestionStyle::Visible) self.question(msg, AuthMessageType::Visible)
} }
fn prompt_blind(&self, msg: &str) -> Result<String, ()> { fn prompt_blind(&self, msg: &str) -> Result<String, ()> {
self.question(msg, QuestionStyle::Secret) self.question(msg, AuthMessageType::Secret)
} }
fn info(&self, msg: &str) -> Result<(), ()> { fn info(&self, msg: &str) -> Result<(), ()> {
self.question(msg, QuestionStyle::Info).map(|_| ()) self.question(msg, AuthMessageType::Info).map(|_| ())
} }
fn error(&self, msg: &str) -> Result<(), ()> { fn error(&self, msg: &str) -> Result<(), ()> {
self.question(msg, QuestionStyle::Error).map(|_| ()) self.question(msg, AuthMessageType::Error).map(|_| ())
} }
} }

View File

@@ -13,7 +13,7 @@ use async_trait::async_trait;
use tokio::net::UnixDatagram as TokioUnixDatagram; use tokio::net::UnixDatagram as TokioUnixDatagram;
use super::worker::{ParentToSessionChild, QuestionStyle, SessionChildToParent}; use super::worker::{AuthMessageType, ParentToSessionChild, SessionChildToParent};
use crate::error::Error; use crate::error::Error;
#[async_trait] #[async_trait]
@@ -78,7 +78,7 @@ impl SessionChild {
#[derive(Debug)] #[derive(Debug)]
pub enum SessionState { pub enum SessionState {
Question(QuestionStyle, String), Question(AuthMessageType, String),
Ready, Ready,
} }
@@ -158,9 +158,9 @@ impl Session {
Ok(()) Ok(())
} }
/// Send an answer to an authentication question, or None to cahncel the /// Send a response to an authentication question, or None to cancel the
/// authentication attempt. /// authentication attempt.
pub async fn post_answer(&mut self, answer: Option<String>) -> Result<(), Error> { pub async fn post_response(&mut self, answer: Option<String>) -> Result<(), Error> {
self.last_msg = None; self.last_msg = None;
let msg = match answer { let msg = match answer {
Some(resp) => ParentToSessionChild::PamResponse { resp }, Some(resp) => ParentToSessionChild::PamResponse { resp },

View File

@@ -15,7 +15,7 @@ use super::{
use crate::{error::Error, pam::session::PamSession, terminal}; use crate::{error::Error, pam::session::PamSession, terminal};
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum QuestionStyle { pub enum AuthMessageType {
Visible, Visible,
Secret, Secret,
Info, Info,
@@ -55,7 +55,7 @@ impl ParentToSessionChild {
pub enum SessionChildToParent { pub enum SessionChildToParent {
Success, Success,
Error(Error), Error(Error),
PamMessage { style: QuestionStyle, msg: String }, PamMessage { style: AuthMessageType, msg: String },
FinalChildPid(u64), FinalChildPid(u64),
} }