Rename Question to Message
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -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)",
|
||||
|
24
README.md
24
README.md
@@ -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"
|
||||
}
|
||||
```
|
@@ -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 => {
|
||||
|
@@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -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()),
|
||||
}
|
||||
}
|
||||
|
@@ -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),
|
||||
};
|
||||
|
@@ -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(|_| ())
|
||||
}
|
||||
}
|
||||
|
@@ -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 },
|
||||
|
@@ -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),
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user