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.
[[package]]
name = "agreety"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"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)",
"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)",
@@ -162,7 +162,7 @@ dependencies = [
[[package]]
name = "greet_proto"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"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)",
@@ -174,12 +174,12 @@ dependencies = [
[[package]]
name = "greetd"
version = "0.1.1"
version = "0.2.0"
dependencies = [
"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)",
"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)",
"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)",

View File

@@ -56,13 +56,13 @@ The greeter runs as a configured user, which is supposed to be one with no inter
# 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.
@@ -79,14 +79,14 @@ Create a new session for the given user. This may result in authentication quest
}
```
### AnswerAuthQuestion
### PostAuthMessageResponse
Answer an authentication question.
```
{
"type": "answer_auth_question",
"answer": "password"
"type": "post_auth_message_response",
"response": "password"
}
```
@@ -140,14 +140,14 @@ The action failed.
```
### AuthQuestion
### AuthMessage
The action resulted in authentication questions.
```
{
"type": "auth_question",
"question": "Password: ",
"style": "secret"
"type": "auth_message",
"message": "Password: ",
"message_type": "secret"
}
```

View File

@@ -9,7 +9,7 @@ use ini::Ini;
use nix::sys::utsname::uname;
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>> {
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)?;
match Response::read_from(&mut stream)? {
Response::AuthQuestion { question, style } => {
let answer = match style {
QuestionStyle::Visible => prompt_stderr(&question)?,
QuestionStyle::Secret => prompt_password_stderr(&question)?,
QuestionStyle::Info => {
eprintln!("info: {}", question);
Response::AuthMessage {
auth_message,
auth_message_type,
} => {
let answer = match auth_message_type {
AuthMessageType::Visible => prompt_stderr(&auth_message)?,
AuthMessageType::Secret => prompt_password_stderr(&auth_message)?,
AuthMessageType::Info => {
eprintln!("info: {}", auth_message);
"".to_string()
}
QuestionStyle::Error => {
eprintln!("error: {}", question);
AuthMessageType::Error => {
eprintln!("error: {}", auth_message);
"".to_string()
}
};
next_request = Request::AnswerAuthQuestion {
answer: Some(answer),
next_request = Request::PostAuthMessageResponse {
response: Some(answer),
};
}
Response::Success => {

View File

@@ -46,28 +46,28 @@ use serde::{Deserialize, Serialize};
#[serde(tag = "type")]
pub enum Request {
/// 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.
///
/// If a question is returned, it should be answered with a
/// Request::AnswerAuthQuestion. If a success is returned, the session can
/// then be started with Request::StartSession.
/// If an auth message is returned, it should be answered with a
/// Request::PostAuthMessageResponse. If a success is returned, the session
/// can then be started with Request::StartSession.
///
/// If a login flow needs to be aborted at any point, send
/// Request::CancelSession. Note that the session is cancelled
/// automatically on error.
CreateSession { username: String },
/// AnswerAuthQuestion answers the last auth question, and returns either
/// a Response::AuthQuestion, Response::Success or Response::Failure.
/// PostAuthMessageResponse responds to the last auth message, and returns
/// either a Response::AuthMessage, Response::Success or Response::Failure.
///
/// If a question is returned, it should be answered with a
/// Request::AnswerAuthQuestion. If a success is returned, the session can
/// then be started with Request::StartSession.
AnswerAuthQuestion { answer: Option<String> },
/// If an auth message is returned, it should be answered with a
/// Request::PostAuthMessageResponse. If a success is returned, the session
/// can then be started with Request::StartSession.
PostAuthMessageResponse { response: Option<String> },
/// 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> },
/// Cancel a session. This can only be done if the session has not been
@@ -87,10 +87,10 @@ pub enum ErrorType {
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)]
#[serde(rename_all = "snake_case")]
pub enum QuestionStyle {
pub enum AuthMessageType {
/// A question whose answer should be visible during input.
Visible,
@@ -111,9 +111,9 @@ pub enum QuestionStyle {
///
/// ```json
/// {
/// "type": "auth_question",
/// "question": "Password:",
/// "style": "secret"
/// "type": "auth_message",
/// "message": "Password:",
/// "message_type": "secret"
/// }
/// ```
#[derive(Debug, Deserialize, Serialize)]
@@ -130,18 +130,18 @@ pub enum Response {
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.
///
/// 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
/// 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
/// no assumptions are made about the questions that will be asked, and
/// attempts to automatically answer these questions should not be made.
AuthQuestion {
style: QuestionStyle,
question: String,
AuthMessage {
auth_message_type: AuthMessageType,
auth_message: String,
},
}

View File

@@ -10,10 +10,10 @@ use crate::{
error::Error,
session::{
interface::{Session, SessionChild, SessionState},
worker::QuestionStyle as SessQuestionStyle,
worker::AuthMessageType as SessAuthMessageType,
},
};
use greet_proto::QuestionStyle;
use greet_proto::AuthMessageType;
struct SessionChildSet {
child: SessionChild,
@@ -139,17 +139,17 @@ impl Context {
}
/// 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;
match &mut inner.configuring {
Some(s) => match s.session.get_state().await? {
SessionState::Ready => Ok(None),
SessionState::Question(style, string) => Ok(Some((
match style {
SessQuestionStyle::Visible => QuestionStyle::Visible,
SessQuestionStyle::Secret => QuestionStyle::Secret,
SessQuestionStyle::Info => QuestionStyle::Info,
SessQuestionStyle::Error => QuestionStyle::Error,
SessAuthMessageType::Visible => AuthMessageType::Visible,
SessAuthMessageType::Secret => AuthMessageType::Secret,
SessAuthMessageType::Info => AuthMessageType::Info,
SessAuthMessageType::Error => AuthMessageType::Error,
},
string,
))),
@@ -159,10 +159,10 @@ impl Context {
}
/// 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;
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()),
}
}

View File

@@ -42,9 +42,9 @@ fn wrap_result<T>(res: Result<T, Error>) -> Response {
async fn client_get_question(ctx: &Context) -> Response {
match ctx.get_question().await {
Ok(Some((style, msg))) => Response::AuthQuestion {
style,
question: msg,
Ok(Some((auth_message_type, auth_message))) => Response::AuthMessage {
auth_message_type,
auth_message,
},
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,
res => wrap_result(res),
},
Request::AnswerAuthQuestion { answer } => match ctx.post_answer(answer).await {
Ok(()) => client_get_question(&ctx).await,
res => wrap_result(res),
},
Request::PostAuthMessageResponse { response } => {
match ctx.post_response(response).await {
Ok(()) => client_get_question(&ctx).await,
res => wrap_result(res),
}
}
Request::StartSession { cmd, env } => wrap_result(ctx.start(cmd, env).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;
/// SessionConv is a PAM conversation implementation that forwards questions
@@ -8,7 +8,7 @@ pub struct 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 {
style,
msg: msg.to_string(),
@@ -34,15 +34,15 @@ impl<'a> SessionConv<'a> {
impl<'a> Converse for SessionConv<'a> {
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, ()> {
self.question(msg, QuestionStyle::Secret)
self.question(msg, AuthMessageType::Secret)
}
fn info(&self, msg: &str) -> Result<(), ()> {
self.question(msg, QuestionStyle::Info).map(|_| ())
self.question(msg, AuthMessageType::Info).map(|_| ())
}
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 super::worker::{ParentToSessionChild, QuestionStyle, SessionChildToParent};
use super::worker::{AuthMessageType, ParentToSessionChild, SessionChildToParent};
use crate::error::Error;
#[async_trait]
@@ -78,7 +78,7 @@ impl SessionChild {
#[derive(Debug)]
pub enum SessionState {
Question(QuestionStyle, String),
Question(AuthMessageType, String),
Ready,
}
@@ -158,9 +158,9 @@ impl Session {
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.
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;
let msg = match answer {
Some(resp) => ParentToSessionChild::PamResponse { resp },

View File

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