dummy ssh connect
This commit is contained in:
parent
c87b60a738
commit
bec3952861
@ -23,7 +23,7 @@ actix-web-actors = "3.0.0"
|
||||
urlencoding = "2.1.0"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
|
||||
trust-dns-resolver = "0.20"
|
||||
rand = "0.8"
|
||||
|
||||
# log systems
|
||||
|
64
backend/src/agent/agent.rs
Normal file
64
backend/src/agent/agent.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use actix::{Actor, Addr, Context, Handler, Message, MessageResponse};
|
||||
use actix_web::web::Bytes;
|
||||
use std::net::*;
|
||||
|
||||
use log::info;
|
||||
#[derive(MessageResponse)]
|
||||
pub enum AgentResp {
|
||||
Success,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "AgentResp")]
|
||||
pub enum AgentMsg {
|
||||
ConnectServer(SocketAddr),
|
||||
SendToServer(Bytes),
|
||||
SendToClient(Bytes),
|
||||
}
|
||||
|
||||
pub struct Agent {
|
||||
id: u32,
|
||||
server_info: Option<SocketAddr>,
|
||||
server_stream: Option<TcpStream>,
|
||||
// client_info: SocketAddr,
|
||||
}
|
||||
|
||||
impl Actor for Agent {
|
||||
type Context = Context<Self>;
|
||||
}
|
||||
|
||||
impl Handler<AgentMsg> for Agent {
|
||||
type Result = AgentResp;
|
||||
|
||||
fn handle(&mut self, msg: AgentMsg, _ctx: &mut Context<Self>) -> Self::Result {
|
||||
match msg {
|
||||
AgentMsg::ConnectServer(addr) => {
|
||||
info!("connect to server: {}", addr);
|
||||
self.server_info = Some(addr);
|
||||
if let Ok(stream) = TcpStream::connect(addr) {
|
||||
stream
|
||||
.set_nonblocking(true)
|
||||
.expect("set_nonblocking call failed");
|
||||
self.server_stream = Some(stream);
|
||||
AgentResp::Success
|
||||
} else {
|
||||
AgentResp::Failed
|
||||
}
|
||||
}
|
||||
AgentMsg::SendToServer(_data) => AgentResp::Success,
|
||||
AgentMsg::SendToClient(_data) => AgentResp::Success,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Agent {
|
||||
pub fn new(id: u32) -> Addr<Agent> {
|
||||
Self {
|
||||
id,
|
||||
server_info: None,
|
||||
server_stream: None,
|
||||
}
|
||||
.start()
|
||||
}
|
||||
}
|
4
backend/src/agent/mod.rs
Normal file
4
backend/src/agent/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod remote;
|
||||
pub mod ws;
|
||||
pub mod resolver;
|
||||
pub mod agent;
|
88
backend/src/agent/remote.rs
Normal file
88
backend/src/agent/remote.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use actix_session::Session;
|
||||
use actix_web::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use log::info;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::agent::resolver::*;
|
||||
use crate::AppData;
|
||||
|
||||
use super::agent;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct RemoteInfo {
|
||||
#[serde(default)]
|
||||
host: String,
|
||||
#[serde(default)]
|
||||
ip: String,
|
||||
#[serde(default)]
|
||||
port: u16,
|
||||
}
|
||||
|
||||
#[post("/target/validate")]
|
||||
pub async fn target_validate(
|
||||
data: web::Data<AppData>,
|
||||
params: web::Json<RemoteInfo>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let remote = params.into_inner();
|
||||
info!("{:?}", remote);
|
||||
let resolved = data.resolver.send(ResolveMsg::Resolve(remote.host)).await;
|
||||
|
||||
match resolved.unwrap() {
|
||||
ResolveResp::Success(ipaddr) => {
|
||||
let json = json!({
|
||||
"status": "success",
|
||||
"ip": ipaddr
|
||||
});
|
||||
Ok(HttpResponse::Ok().json(json))
|
||||
}
|
||||
_ => {
|
||||
let json = json!({
|
||||
"status": "failed",
|
||||
"message": "Failed to resolve the target name"
|
||||
});
|
||||
Ok(HttpResponse::Ok().json(json))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/target/ssh")]
|
||||
pub async fn target_ssh(
|
||||
session: Session,
|
||||
data: web::Data<AppData>,
|
||||
params: web::Json<RemoteInfo>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let aid = rand::thread_rng().gen::<u32>();
|
||||
let remote = params.into_inner();
|
||||
let agent = agent::Agent::new(aid);
|
||||
|
||||
match agent
|
||||
.send(agent::AgentMsg::ConnectServer(
|
||||
format!("{}:{}", remote.ip, remote.port).parse().unwrap(),
|
||||
))
|
||||
.await
|
||||
{
|
||||
Ok(agent::AgentResp::Success) => {
|
||||
// add to agent list
|
||||
data.agents.write().unwrap().insert(aid, agent);
|
||||
|
||||
// add session, so that the websocket can send message to the agent
|
||||
let _ = session.set::<u32>("aid", aid);
|
||||
|
||||
// send response
|
||||
let json = json!({
|
||||
"status": "success",
|
||||
});
|
||||
Ok(HttpResponse::Ok().json(json))
|
||||
}
|
||||
_ => {
|
||||
let json = json!({
|
||||
"status": "failed",
|
||||
"message": "Failed to connect to the target"
|
||||
});
|
||||
Ok(HttpResponse::Ok().json(json))
|
||||
}
|
||||
}
|
||||
}
|
75
backend/src/agent/resolver.rs
Normal file
75
backend/src/agent/resolver.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use actix::{Actor, Addr, Context, Handler, Message, MessageResponse};
|
||||
|
||||
use std::net::*;
|
||||
use trust_dns_resolver::config::*;
|
||||
use trust_dns_resolver::Resolver;
|
||||
|
||||
use log::info;
|
||||
|
||||
#[derive(MessageResponse)]
|
||||
pub enum ResolveResp {
|
||||
Success(IpAddr),
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "ResolveResp")]
|
||||
pub enum ResolveMsg {
|
||||
Resolve(String),
|
||||
}
|
||||
|
||||
pub struct DnsResolver {
|
||||
resolver: Resolver,
|
||||
}
|
||||
|
||||
impl Actor for DnsResolver {
|
||||
type Context = Context<Self>;
|
||||
}
|
||||
|
||||
impl Handler<ResolveMsg> for DnsResolver {
|
||||
type Result = ResolveResp;
|
||||
|
||||
fn handle(&mut self, msg: ResolveMsg, _: &mut Context<Self>) -> Self::Result {
|
||||
match msg {
|
||||
ResolveMsg::Resolve(name) => {
|
||||
if let Ok(response) = self.resolver.lookup_ip(name.clone()) {
|
||||
if let Some(address) = response.iter().next() {
|
||||
info!("Resolved {} to {}", name, address);
|
||||
ResolveResp::Success(address)
|
||||
} else {
|
||||
ResolveResp::Failed
|
||||
}
|
||||
} else {
|
||||
info!("Failed to resolve {}", name);
|
||||
ResolveResp::Failed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsResolver {
|
||||
pub fn new() -> Addr<Self> {
|
||||
let resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();
|
||||
|
||||
DnsResolver { resolver }.start()
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a new Resolver with default configuration options
|
||||
// let mut resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();
|
||||
|
||||
// On Unix/Posix systems, this will read the /etc/resolv.conf
|
||||
// let mut resolver = Resolver::from_system_conf().unwrap();
|
||||
|
||||
// Lookup the IP addresses associated with a name.
|
||||
// let mut response = resolver.lookup_ip("www.example.com.").unwrap();
|
||||
|
||||
// There can be many addresses associated with the name,
|
||||
// this can return IPv4 and/or IPv6 addresses
|
||||
// let address = response.iter().next().expect("no addresses returned!");
|
||||
// if address.is_ipv4() {
|
||||
// assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
|
||||
// } else {
|
||||
// assert_eq!(address, IpAddr::V6(Ipv6Addr::new(0x2606, 0x2800, 0x220, 0x1, 0x248, 0x1893, 0x25c8, 0x1946)));
|
||||
// }
|
@ -1,18 +1,25 @@
|
||||
use actix::{Actor, StreamHandler};
|
||||
use actix::{Actor, Addr, StreamHandler};
|
||||
use actix_session::Session;
|
||||
use actix_web::*;
|
||||
use actix_web::{web, Error, HttpRequest, HttpResponse};
|
||||
use actix_web_actors::ws;
|
||||
use log::*;
|
||||
|
||||
/// Define HTTP actor
|
||||
struct MyWs;
|
||||
use crate::AppData;
|
||||
|
||||
impl Actor for MyWs {
|
||||
use super::agent::Agent;
|
||||
|
||||
/// Define HTTP actor
|
||||
struct WsSession {
|
||||
agent: Addr<Agent>,
|
||||
}
|
||||
|
||||
impl Actor for WsSession {
|
||||
type Context = ws::WebsocketContext<Self>;
|
||||
}
|
||||
|
||||
/// Handler for ws::Message message
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWs {
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsSession {
|
||||
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||
match msg {
|
||||
Ok(ws::Message::Ping(msg)) => ctx.pong(&msg),
|
||||
@ -24,8 +31,16 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWs {
|
||||
}
|
||||
|
||||
#[get("/ws")]
|
||||
pub async fn ws_index(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, Error> {
|
||||
let resp = ws::start(MyWs {}, &req, stream);
|
||||
pub async fn ws_index(
|
||||
req: HttpRequest,
|
||||
session: Session,
|
||||
data: web::Data<AppData>,
|
||||
stream: web::Payload,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let aid = session.get::<u32>("aid").unwrap_or(Some(0)).unwrap();
|
||||
let agent = data.agents.read().unwrap().get(&aid).unwrap().clone();
|
||||
let resp = ws::start(WsSession { agent }, &req, stream);
|
||||
|
||||
match &resp {
|
||||
Ok(resp) => info!("{:?}", resp),
|
||||
Err(e) => error!("{:?}", e),
|
@ -1,24 +1,43 @@
|
||||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
use actix::Addr;
|
||||
use actix_files as fs;
|
||||
use actix_session::CookieSession;
|
||||
use actix_web::http::{ContentEncoding, StatusCode};
|
||||
use actix_web::*;
|
||||
|
||||
use agent::{agent::Agent, resolver::DnsResolver};
|
||||
use log::info;
|
||||
use rand::Rng;
|
||||
|
||||
mod agent;
|
||||
mod user;
|
||||
mod ws;
|
||||
|
||||
// pub struct AppState ;
|
||||
|
||||
// impl Actor for AppState {
|
||||
// type Context = actix::Context<Self>;
|
||||
// }
|
||||
|
||||
const STATIC_DIR: &str = "./static/";
|
||||
const PAGE_INDEX: &str = "./static/index.html";
|
||||
const PAGE_NOT_FOUND: &str = "./static/p404.html";
|
||||
|
||||
pub struct AppData {
|
||||
// session: CookieSession,
|
||||
resolver: Addr<DnsResolver>,
|
||||
agents: RwLock<HashMap<u32, Addr<Agent>>>,
|
||||
}
|
||||
|
||||
impl AppData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
resolver: DnsResolver::new(),
|
||||
agents: RwLock::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AppData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_logger() {
|
||||
let logger = femme::pretty::Logger::new();
|
||||
async_log::Logger::wrap(logger, || 12)
|
||||
@ -43,12 +62,14 @@ async fn main() -> std::io::Result<()> {
|
||||
let private_key = rand::thread_rng().gen::<[u8; 32]>();
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
// .data(AppState)
|
||||
.data(AppData::new())
|
||||
.wrap(CookieSession::signed(&private_key).secure(false))
|
||||
.wrap(middleware::Compress::new(ContentEncoding::Gzip))
|
||||
.service(index)
|
||||
.service(ws::ws_index)
|
||||
.service(user::auth::auth)
|
||||
.service(agent::remote::target_validate)
|
||||
.service(agent::remote::target_ssh)
|
||||
.service(agent::ws::ws_index)
|
||||
.service(
|
||||
fs::Files::new("/static", STATIC_DIR)
|
||||
.prefer_utf8(true)
|
||||
|
@ -1,20 +1,24 @@
|
||||
use actix::{Actor, Context, Handler, Message, MessageResponse};
|
||||
use actix_session::Session;
|
||||
use actix_web::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use log::info;
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "Self")]
|
||||
#[derive(MessageResponse)]
|
||||
#[allow(dead_code)]
|
||||
enum AuthMessage {
|
||||
DoAuth,
|
||||
enum AuthResp {
|
||||
AuthSuccess,
|
||||
AuthFailure,
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "AuthResp")]
|
||||
enum AuthMsg {
|
||||
DoAuth,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct AuthInfo {
|
||||
username: String,
|
||||
@ -34,12 +38,12 @@ impl Actor for AuthInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler<AuthMessage> for AuthInfo {
|
||||
type Result = AuthMessage;
|
||||
impl Handler<AuthMsg> for AuthInfo {
|
||||
type Result = AuthResp;
|
||||
|
||||
fn handle(&mut self, _msg: AuthMessage, _ctx: &mut Context<Self>) -> Self::Result {
|
||||
fn handle(&mut self, _msg: AuthMsg, _ctx: &mut Context<Self>) -> Self::Result {
|
||||
info!("AuthInfo handle");
|
||||
AuthMessage::AuthSuccess
|
||||
AuthResp::AuthSuccess
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,15 +51,12 @@ impl Handler<AuthMessage> for AuthInfo {
|
||||
pub async fn auth(params: web::Json<AuthInfo>) -> Result<HttpResponse, Error> {
|
||||
let auth = params.into_inner();
|
||||
let auth_addr = auth.start();
|
||||
let res = auth_addr.send(AuthMessage::DoAuth).await;
|
||||
let res = auth_addr.send(AuthMsg::DoAuth).await;
|
||||
|
||||
match res {
|
||||
Ok(AuthMessage::AuthSuccess) => Ok(HttpResponse::Ok().json(json!({
|
||||
Ok(AuthResp::AuthSuccess) => Ok(HttpResponse::Ok().json(json!({
|
||||
"status": "success",
|
||||
}))),
|
||||
Ok(AuthMessage::AuthFailure) => Ok(HttpResponse::Ok().json(json!({
|
||||
"status": "failure",
|
||||
}))),
|
||||
_ => Ok(HttpResponse::Ok().json(json!({
|
||||
"status": "failure",
|
||||
}))),
|
||||
|
142
frontend/src/components/host.rs
Normal file
142
frontend/src/components/host.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use serde_json::{json, Value};
|
||||
use yew::{
|
||||
format::Json,
|
||||
prelude::*,
|
||||
services::{
|
||||
fetch::{FetchTask, Request, Response},
|
||||
ConsoleService, FetchService,
|
||||
},
|
||||
};
|
||||
|
||||
pub enum HostMsg {
|
||||
UpdateHost(String),
|
||||
UpdatePort(String),
|
||||
ValidateResponse(Result<Value, anyhow::Error>),
|
||||
ConnectHost,
|
||||
}
|
||||
|
||||
pub struct Host {
|
||||
link: ComponentLink<Self>,
|
||||
host: String,
|
||||
port: u16,
|
||||
error_msg: String,
|
||||
onsubmit: Callback<(String, u16)>,
|
||||
fetch_task: Option<FetchTask>,
|
||||
}
|
||||
|
||||
// Props
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct HostProps {
|
||||
#[prop_or_default]
|
||||
pub onsubmit: Callback<(String, u16)>,
|
||||
}
|
||||
|
||||
impl Component for Host {
|
||||
type Message = HostMsg;
|
||||
type Properties = HostProps;
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Host {
|
||||
link,
|
||||
host: "".to_string(),
|
||||
port: 0,
|
||||
error_msg: "".to_string(),
|
||||
onsubmit: props.onsubmit,
|
||||
fetch_task: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
HostMsg::UpdateHost(host) => {
|
||||
self.host = host;
|
||||
true
|
||||
}
|
||||
HostMsg::UpdatePort(port) => match port.parse::<u16>() {
|
||||
Ok(port) => {
|
||||
self.port = port;
|
||||
true
|
||||
}
|
||||
Err(_) => {
|
||||
self.error_msg = "Port must be a number".to_string();
|
||||
true
|
||||
}
|
||||
},
|
||||
HostMsg::ValidateResponse(response) => {
|
||||
if let Ok(response) = response {
|
||||
self.error_msg = response["status"].to_string();
|
||||
|
||||
if "\"success\"" == self.error_msg {
|
||||
let mut ip = response["ip"].to_string();
|
||||
let _ = ip.pop();
|
||||
let _ = ip.remove(0);
|
||||
self.onsubmit.emit((ip, self.port));
|
||||
} else {
|
||||
self.error_msg = response["message"].to_string();
|
||||
}
|
||||
} else {
|
||||
self.error_msg = String::from("Valid host failed with unknown reason");
|
||||
ConsoleService::error(&format!("{:?}", response.unwrap_err().to_string()));
|
||||
}
|
||||
// release resources
|
||||
self.fetch_task = None;
|
||||
true
|
||||
}
|
||||
HostMsg::ConnectHost => {
|
||||
let to_post = json!({
|
||||
"host": self.host,
|
||||
});
|
||||
|
||||
// 1. build the request
|
||||
let request = Request::post("/target/validate")
|
||||
.header("Content-Type", "application/json")
|
||||
.body(Json(&to_post))
|
||||
.expect("Could not build auth request.");
|
||||
// 2. construct a callback
|
||||
let callback =
|
||||
self.link
|
||||
.callback(|response: Response<Json<Result<Value, anyhow::Error>>>| {
|
||||
// ConsoleService::error(&format!("{:?}", response));
|
||||
let Json(data) = response.into_body();
|
||||
HostMsg::ValidateResponse(data)
|
||||
});
|
||||
// 3. pass the request and callback to the fetch service
|
||||
let task = FetchService::fetch(request, callback).expect("failed to start request");
|
||||
// 4. store the task so it isn't canceled immediately
|
||||
self.fetch_task = Some(task);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let updatehost = self.link.callback(|e: ChangeData| match e {
|
||||
ChangeData::Value(val) => HostMsg::UpdateHost(val),
|
||||
_ => panic!("unexpected message"),
|
||||
});
|
||||
|
||||
let updateport = self.link.callback(|e: ChangeData| match e {
|
||||
ChangeData::Value(val) => HostMsg::UpdatePort(val),
|
||||
_ => panic!("unexpected message"),
|
||||
});
|
||||
|
||||
let connecthost = self.link.callback(|_| HostMsg::ConnectHost);
|
||||
|
||||
html! {
|
||||
<div class="horizontal-centre vertical-centre">
|
||||
<label for="hostname">{"Hostname: "}</label>
|
||||
<input id="hostname" type="text" placeholder="hostname" onchange={updatehost} />
|
||||
<br />
|
||||
<input id="port" type="text" placeholder="port" onchange={updateport}/>
|
||||
<br />
|
||||
<button onclick={connecthost}>{"Connect"}</button>
|
||||
<br />
|
||||
{self.error_msg.clone()}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod auth;
|
||||
pub mod host;
|
@ -1,28 +1,113 @@
|
||||
use yew::prelude::*;
|
||||
use serde_json::{json, Value};
|
||||
use yew::{
|
||||
format::Json,
|
||||
prelude::*,
|
||||
services::{
|
||||
fetch::{FetchTask, Request, Response},
|
||||
ConsoleService, FetchService,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct PageSsh {}
|
||||
use crate::components;
|
||||
|
||||
pub enum Msg {}
|
||||
pub struct PageSsh {
|
||||
link: ComponentLink<Self>,
|
||||
target: (String, u16),
|
||||
error_msg: String,
|
||||
fetch_task: Option<FetchTask>,
|
||||
connected: bool,
|
||||
}
|
||||
|
||||
pub enum SshMsg {
|
||||
SshConnect((String, u16)),
|
||||
SshConnectResp(Result<Value, anyhow::Error>),
|
||||
SshConnected,
|
||||
}
|
||||
|
||||
impl Component for PageSsh {
|
||||
type Message = Msg;
|
||||
type Message = SshMsg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
PageSsh {}
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
PageSsh {
|
||||
link,
|
||||
target: (String::from(""), 0),
|
||||
error_msg: String::from(""),
|
||||
fetch_task: None,
|
||||
connected: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
SshMsg::SshConnect(target) => {
|
||||
self.target = target;
|
||||
// ConsoleService::log(&self.target);
|
||||
let to_post = json!({
|
||||
"ip": self.target.0,
|
||||
"port": self.target.1,
|
||||
});
|
||||
|
||||
// 1. build the request
|
||||
let request = Request::post("/target/ssh")
|
||||
.header("Content-Type", "application/json")
|
||||
.body(Json(&to_post))
|
||||
.expect("Could not build auth request.");
|
||||
// 2. construct a callback
|
||||
let callback =
|
||||
self.link
|
||||
.callback(|response: Response<Json<Result<Value, anyhow::Error>>>| {
|
||||
// ConsoleService::error(&format!("{:?}", response));
|
||||
let Json(data) = response.into_body();
|
||||
SshMsg::SshConnectResp(data)
|
||||
});
|
||||
// 3. pass the request and callback to the fetch service
|
||||
let task = FetchService::fetch(request, callback).expect("failed to start request");
|
||||
// 4. store the task so it isn't canceled immediately
|
||||
self.fetch_task = Some(task);
|
||||
true
|
||||
}
|
||||
SshMsg::SshConnectResp(response) => {
|
||||
if let Ok(response) = response {
|
||||
self.error_msg = response["status"].to_string();
|
||||
|
||||
if "\"success\"" == self.error_msg {
|
||||
self.link.send_message(SshMsg::SshConnected);
|
||||
} else {
|
||||
self.error_msg = response["message"].to_string();
|
||||
}
|
||||
} else {
|
||||
self.error_msg = String::from("Connect host failed with unknown reason");
|
||||
ConsoleService::error(&format!("{:?}", response.unwrap_err().to_string()));
|
||||
}
|
||||
// release resources
|
||||
self.fetch_task = None;
|
||||
true
|
||||
}
|
||||
SshMsg::SshConnected => {
|
||||
self.connected = true;
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, _: Self::Properties) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let connect_ssh = self.link.callback(SshMsg::SshConnect);
|
||||
if !self.connected {
|
||||
html! {
|
||||
<p>{ "Hello ssh!\n\n\n\n" }</p>
|
||||
<>
|
||||
<components::host::Host onsubmit=connect_ssh/>
|
||||
{self.error_msg.clone()}
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<></>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user