dummy
This commit is contained in:
parent
a0b1157c04
commit
c8bb376d80
@ -1,3 +1,4 @@
|
|||||||
|
use super::input::Input;
|
||||||
use anyhow;
|
use anyhow;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -116,28 +117,19 @@ impl Component for AuthComponents {
|
|||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let link = &self.link;
|
let link = &self.link;
|
||||||
|
|
||||||
let update_uname = link.callback(|e: ChangeData| match e {
|
let update_uname = link.callback(|v| AuthMsg::UpdateUsername(v));
|
||||||
ChangeData::Value(val) => AuthMsg::UpdateUsername(val),
|
|
||||||
_ => panic!("unexpected message"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let update_pword = link.callback(|e: ChangeData| match e {
|
let update_pword = link.callback(|v| AuthMsg::UpdatePassword(v));
|
||||||
ChangeData::Value(val) => AuthMsg::UpdatePassword(val),
|
|
||||||
_ => panic!("unexpected message"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let auth_post = link.callback(|_| {
|
let auth_post = link.callback(|_| AuthMsg::AuthRequest);
|
||||||
// ConsoleService::log("Auth post");
|
|
||||||
AuthMsg::AuthRequest
|
|
||||||
});
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="horizontal-centre vertical-centre">
|
<div class="horizontal-centre vertical-centre">
|
||||||
<label for="username">{"Username: "}</label>
|
<label for="username">{"Username: "}</label>
|
||||||
<input id="username" type="text" placeholder="Username" onchange={update_uname} />
|
<Input id="username" type_="text" placeholder="Username" on_change={update_uname} />
|
||||||
<br />
|
<br />
|
||||||
<label for="password">{"Password: "}</label>
|
<label for="password">{"Password: "}</label>
|
||||||
<input id="password" type="password" placeholder="Password" onchange={update_pword} />
|
<Input id="password" type_="password" placeholder="Password" on_change={update_pword} />
|
||||||
<br />
|
<br />
|
||||||
<button type="submit" onclick={auth_post}>{"Login"}</button>
|
<button type="submit" onclick={auth_post}>{"Login"}</button>
|
||||||
<br />
|
<br />
|
||||||
|
68
frontend/src/components/input.rs
Normal file
68
frontend/src/components/input.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
// message on update
|
||||||
|
pub enum InputMsg {
|
||||||
|
Update(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// props on_change
|
||||||
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
pub struct InputProps {
|
||||||
|
pub on_change: Callback<String>,
|
||||||
|
pub id: String,
|
||||||
|
pub type_: String,
|
||||||
|
pub placeholder: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// component input
|
||||||
|
pub struct Input {
|
||||||
|
link: ComponentLink<Self>,
|
||||||
|
on_change: Callback<String>,
|
||||||
|
id: String,
|
||||||
|
type_: String,
|
||||||
|
placeholder: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Input {
|
||||||
|
type Message = InputMsg;
|
||||||
|
type Properties = InputProps;
|
||||||
|
|
||||||
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
|
Input {
|
||||||
|
link,
|
||||||
|
on_change: props.on_change,
|
||||||
|
id: props.id,
|
||||||
|
type_: props.type_,
|
||||||
|
placeholder: props.placeholder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
match msg {
|
||||||
|
InputMsg::Update(text) => {
|
||||||
|
self.on_change.emit(text);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Html {
|
||||||
|
let on_change = self.link.callback(|e: ChangeData| match e {
|
||||||
|
ChangeData::Value(v) => InputMsg::Update(v),
|
||||||
|
_ => panic!("unexpected message"),
|
||||||
|
});
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<input
|
||||||
|
id={self.id.clone()}
|
||||||
|
type={self.type_.clone()}
|
||||||
|
placeholder={self.placeholder.clone()}
|
||||||
|
onchange={on_change}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod host;
|
pub mod host;
|
||||||
|
pub mod input;
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
|
@ -104,6 +104,7 @@ impl Component for WebsocketCtx {
|
|||||||
|
|
||||||
fn rendered(&mut self, first_render: bool) {
|
fn rendered(&mut self, first_render: bool) {
|
||||||
if first_render && self.ws.is_none() {
|
if first_render && self.ws.is_none() {
|
||||||
|
ConsoleService::log(&format!("Start websocket"));
|
||||||
self.link.send_message(WebsocketMsg::Connect);
|
self.link.send_message(WebsocketMsg::Connect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,8 @@ use yew::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::components::ws::WebsocketMsg;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components,
|
components::{self, input::Input, ws::WebsocketMsg},
|
||||||
protocal::{common::*, vnc::VncHandler},
|
protocal::{common::*, vnc::VncHandler},
|
||||||
utils::WeakComponentLink,
|
utils::WeakComponentLink,
|
||||||
};
|
};
|
||||||
@ -24,6 +23,10 @@ pub struct PageRemote {
|
|||||||
connected: bool,
|
connected: bool,
|
||||||
handler: ProtocalHandler<VncHandler>,
|
handler: ProtocalHandler<VncHandler>,
|
||||||
ws_link: WeakComponentLink<components::ws::WebsocketCtx>,
|
ws_link: WeakComponentLink<components::ws::WebsocketCtx>,
|
||||||
|
request_username: bool,
|
||||||
|
request_password: bool,
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
@ -35,6 +38,9 @@ pub enum RemoteMsg {
|
|||||||
Connected,
|
Connected,
|
||||||
Recv(Vec<u8>),
|
Recv(Vec<u8>),
|
||||||
Send(Vec<u8>),
|
Send(Vec<u8>),
|
||||||
|
UpdateUsername(String),
|
||||||
|
UpdatePassword(String),
|
||||||
|
SendCredential,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for PageRemote {
|
impl Component for PageRemote {
|
||||||
@ -50,6 +56,10 @@ impl Component for PageRemote {
|
|||||||
connected: false,
|
connected: false,
|
||||||
handler: ProtocalHandler::new(),
|
handler: ProtocalHandler::new(),
|
||||||
ws_link: WeakComponentLink::default(),
|
ws_link: WeakComponentLink::default(),
|
||||||
|
request_username: false,
|
||||||
|
request_password: false,
|
||||||
|
username: String::from(""),
|
||||||
|
password: String::from(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +125,11 @@ impl Component for PageRemote {
|
|||||||
self.link.send_message(RemoteMsg::Send(out));
|
self.link.send_message(RemoteMsg::Send(out));
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
ProtocalHandlerOutput::RequirePassword => {
|
||||||
|
self.request_password = true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RemoteMsg::Send(v) => {
|
RemoteMsg::Send(v) => {
|
||||||
@ -125,6 +140,20 @@ impl Component for PageRemote {
|
|||||||
.send_message(WebsocketMsg::Send(Ok(v)));
|
.send_message(WebsocketMsg::Send(Ok(v)));
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
RemoteMsg::UpdateUsername(username) => {
|
||||||
|
self.username = username;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
RemoteMsg::UpdatePassword(password) => {
|
||||||
|
self.password = password;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
RemoteMsg::SendCredential => {
|
||||||
|
self.request_username = false;
|
||||||
|
self.request_password = false;
|
||||||
|
self.handler.set_credential(&self.username, &self.password);
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +175,61 @@ impl Component for PageRemote {
|
|||||||
let ws_link = &self.ws_link;
|
let ws_link = &self.ws_link;
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<components::ws::WebsocketCtx
|
<div class="horizontal-centre vertical-centre">
|
||||||
weak_link=ws_link onrecv=recv_msg/>
|
{self.username_view()}
|
||||||
{self.error_msg.clone()}
|
{self.password_view()}
|
||||||
|
{self.button_connect_view()}
|
||||||
|
<components::ws::WebsocketCtx
|
||||||
|
weak_link=ws_link onrecv=recv_msg/>
|
||||||
|
{self.error_msg.clone()}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// impl PageRemote
|
||||||
|
impl PageRemote {
|
||||||
|
fn username_view(&self) -> Html {
|
||||||
|
if self.request_username {
|
||||||
|
let update_username = self.link.callback(|v| RemoteMsg::UpdateUsername(v));
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<Input id="username" type_="text" placeholder="username" on_change={update_username}/>
|
||||||
|
<br/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn password_view(&self) -> Html {
|
||||||
|
if self.request_password {
|
||||||
|
let update_password = self.link.callback(|v| RemoteMsg::UpdatePassword(v));
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<Input id="password" type_="password" placeholder="password" on_change={update_password}/>
|
||||||
|
<br/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_connect_view(&self) -> Html {
|
||||||
|
if self.request_username || self.request_password {
|
||||||
|
let send_credential = self.link.callback(|_| RemoteMsg::SendCredential);
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<button type="submit" onclick={send_credential}>{"Connect"}</button>
|
||||||
|
<br/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@ pub enum ProtocalHandlerOutput {
|
|||||||
Ok,
|
Ok,
|
||||||
WsBuf(Vec<u8>),
|
WsBuf(Vec<u8>),
|
||||||
Err(String),
|
Err(String),
|
||||||
|
RequireUsername,
|
||||||
|
RequirePassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProtocalHandler<T>
|
pub struct ProtocalHandler<T>
|
||||||
@ -23,11 +25,16 @@ where
|
|||||||
pub fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
pub fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
||||||
self.inner.handle(input)
|
self.inner.handle(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput {
|
||||||
|
self.inner.set_credential(username, password)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ProtocalImpl {
|
pub trait ProtocalImpl {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput;
|
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput;
|
||||||
|
fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StreamReader<'a> {
|
pub struct StreamReader<'a> {
|
||||||
@ -73,6 +80,12 @@ impl<'a> StreamReader<'a> {
|
|||||||
Some(Self::read_u32(self).map(|b| b as i32)?)
|
Some(Self::read_u32(self).map(|b| b as i32)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extract_slice(&mut self, len: usize, buf: &mut [u8]) {
|
||||||
|
for x in self.inner.by_ref().take(len).enumerate() {
|
||||||
|
buf[x.0] = *x.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_string_with_len(&mut self, len: usize) -> Option<String> {
|
pub fn read_string_with_len(&mut self, len: usize) -> Option<String> {
|
||||||
let mut buf = vec![0u8; len as usize];
|
let mut buf = vec![0u8; len as usize];
|
||||||
self.inner
|
self.inner
|
||||||
@ -85,11 +98,16 @@ impl<'a> StreamReader<'a> {
|
|||||||
Some(String::from_utf8(buf).unwrap())
|
Some(String::from_utf8(buf).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_string(&mut self) -> Option<String> {
|
pub fn read_string_l16(&mut self) -> Option<String> {
|
||||||
let len = self.read_u16()? as usize;
|
let len = self.read_u16()? as usize;
|
||||||
Some(self.read_string_with_len(len)?)
|
Some(self.read_string_with_len(len)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_string_l32(&mut self) -> Option<String> {
|
||||||
|
let len = self.read_u32()? as usize;
|
||||||
|
Some(self.read_string_with_len(len)?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eof(&mut self) -> bool {
|
pub fn eof(&mut self) -> bool {
|
||||||
self.inner.next().is_none()
|
self.inner.next().is_none()
|
||||||
}
|
}
|
||||||
|
@ -6,31 +6,42 @@ const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n";
|
|||||||
const VNC_RFB37: &[u8; 12] = b"RFB 003.007\n";
|
const VNC_RFB37: &[u8; 12] = b"RFB 003.007\n";
|
||||||
const VNC_RFB38: &[u8; 12] = b"RFB 003.008\n";
|
const VNC_RFB38: &[u8; 12] = b"RFB 003.008\n";
|
||||||
const VNC_VER_UNSUPPORTED: &str = "unsupported version";
|
const VNC_VER_UNSUPPORTED: &str = "unsupported version";
|
||||||
|
const VNC_FAILED: &str = "Connection failed with unknow reason";
|
||||||
|
|
||||||
enum VncState {
|
enum VncState {
|
||||||
Handshake,
|
Handshake,
|
||||||
Authentication,
|
Authentication,
|
||||||
|
ClientInit, // auth done
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum SecurityType {
|
pub enum SecurityType {
|
||||||
Unknown(u8),
|
Invalid = 0,
|
||||||
Invalid,
|
None = 1,
|
||||||
None,
|
VncAuth = 2,
|
||||||
VncAuth,
|
RA2 = 5,
|
||||||
AppleRdp,
|
RA2ne = 6,
|
||||||
|
Tight = 16,
|
||||||
|
Ultra = 17,
|
||||||
|
TLS = 18,
|
||||||
|
VeNCrypt = 19,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VncHandler {
|
pub struct VncHandler {
|
||||||
state: VncState,
|
state: VncState,
|
||||||
// output: Vec<u8>,
|
challenge: [u8; 16],
|
||||||
|
security_type: SecurityType,
|
||||||
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocalImpl for VncHandler {
|
impl ProtocalImpl for VncHandler {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
VncHandler {
|
VncHandler {
|
||||||
state: VncState::Handshake,
|
state: VncState::Handshake,
|
||||||
// output: Vec::new(),
|
challenge: [0u8; 16],
|
||||||
|
security_type: SecurityType::Invalid,
|
||||||
|
password: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +58,19 @@ impl ProtocalImpl for VncHandler {
|
|||||||
}
|
}
|
||||||
VncState::Authentication => {
|
VncState::Authentication => {
|
||||||
ConsoleService::log(&format!("{:?}", input));
|
ConsoleService::log(&format!("{:?}", input));
|
||||||
return ProtocalHandlerOutput::Ok;
|
return self.start_authenticate(input);
|
||||||
}
|
}
|
||||||
_ => panic!("unsupported version"),
|
_ => panic!("unsupported version"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_credential(&mut self, _username: &str, password: &str) -> ProtocalHandlerOutput {
|
||||||
|
ConsoleService::log(&format!("{:?}", password));
|
||||||
|
ConsoleService::log(&format!("{:?}", self.challenge));
|
||||||
|
// since vnc do not require username, so we just ignore it
|
||||||
|
self.password = password.to_string();
|
||||||
|
self.continue_authenticate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
@ -59,17 +78,35 @@ impl VncHandler {
|
|||||||
fn handle_handshake(&self, rfbversion: &[u8]) -> Result<&'static [u8], &'static str> {
|
fn handle_handshake(&self, rfbversion: &[u8]) -> Result<&'static [u8], &'static str> {
|
||||||
match rfbversion {
|
match rfbversion {
|
||||||
b"RFB 003.003\n" => Ok(VNC_RFB33),
|
b"RFB 003.003\n" => Ok(VNC_RFB33),
|
||||||
b"RFB 003.007\n" => Ok(VNC_RFB37),
|
b"RFB 003.007\n" => Ok(VNC_RFB33),
|
||||||
b"RFB 003.008\n" => Ok(VNC_RFB38),
|
b"RFB 003.008\n" => Ok(VNC_RFB33),
|
||||||
_ => Err(VNC_VER_UNSUPPORTED),
|
_ => Err(VNC_VER_UNSUPPORTED),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn handle_authenticate(&mut self, auth: &[u8]) -> Result<&'static [u8], &'static str> {
|
fn start_authenticate(&mut self, auth: &[u8]) -> ProtocalHandlerOutput {
|
||||||
match auth {
|
let mut sr = StreamReader::new(auth);
|
||||||
b"NONE\n" => Ok(b"\x00"),
|
match sr.read_u32() {
|
||||||
b"VNCAUTH\n" => Ok(b"\x01"),
|
Some(0) => {
|
||||||
b"APPLETALK\n" => Ok(b"\x02"),
|
let err_msg = sr.read_string_l32().unwrap();
|
||||||
_ => Err(VNC_VER_UNSUPPORTED),
|
ProtocalHandlerOutput::Err(err_msg)
|
||||||
|
}
|
||||||
|
Some(1) => {
|
||||||
|
self.state = VncState::ClientInit;
|
||||||
|
self.client_initialisation()
|
||||||
|
}
|
||||||
|
Some(2) => {
|
||||||
|
sr.extract_slice(16, &mut self.challenge);
|
||||||
|
ProtocalHandlerOutput::RequirePassword
|
||||||
|
}
|
||||||
|
_ => ProtocalHandlerOutput::Err(VNC_FAILED.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_initialisation(&mut self) -> ProtocalHandlerOutput {
|
||||||
|
ProtocalHandlerOutput::Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
fn continue_authenticate(&mut self) -> ProtocalHandlerOutput {
|
||||||
|
ProtocalHandlerOutput::Ok
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user