初始提交:
1. 添加登陆和验证相关code。已ok 2. 获取数据并放置到剪切板相关code 已ok 3. 定义交互的数据头,以便于长msg的切割: ${index}@${revicesize}@ index: 拆分后的数据包的编号两个字符使用ascii编码 revicesize:已接收的数据的长度,三个字符 4. 新建一个线程去持续监听:当鼠标焦点移开某应用程序窗口时触发获取
This commit is contained in:
parent
f01527291a
commit
a77a15f6b6
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "clipboard_sync"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.39.2", features = ["macros", "rt-multi-thread"] }
|
||||||
|
tokio-macros = "2.4.0"
|
||||||
|
reqwest="0.12.5"
|
||||||
|
log="0.4.22"
|
||||||
|
env_logger="0.8"
|
||||||
|
url = "2.2"
|
||||||
|
percent-encoding = "2.1"
|
||||||
|
trust-dns-resolver = "0.20"
|
||||||
|
select = "0.5"
|
||||||
|
scraper = "0.12"
|
||||||
|
arboard = "3.4.0"
|
174
src/lib.rs
Normal file
174
src/lib.rs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
||||||
|
use reqwest::header::{HeaderMap, CONTENT_TYPE, COOKIE};
|
||||||
|
use reqwest::{Client, Response};
|
||||||
|
use scraper::{Html, Selector};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
|
use std::thread;
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
pub mod wclip;
|
||||||
|
pub struct ClipboardSync {
|
||||||
|
user_name: String,
|
||||||
|
password: String,
|
||||||
|
web: Client,
|
||||||
|
ip: String,
|
||||||
|
cookies: String,
|
||||||
|
clip: wclip::Wclip,
|
||||||
|
}
|
||||||
|
|
||||||
|
const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42";
|
||||||
|
|
||||||
|
fn quote(input: &String) -> String {
|
||||||
|
percent_encode(input.as_bytes(), NON_ALPHANUMERIC).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClipboardMsgs {
|
||||||
|
pub msgs: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClipboardSync {
|
||||||
|
pub fn new(ip: &str, user_name: &str, password: &str) -> ClipboardSync {
|
||||||
|
ClipboardSync {
|
||||||
|
user_name: user_name.to_string(),
|
||||||
|
password: password.to_string(),
|
||||||
|
web: Client::new(),
|
||||||
|
ip: ip.to_string(),
|
||||||
|
cookies: "".to_string(),
|
||||||
|
clip: wclip::Wclip::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(&mut self) Result<(), Box<dyn Error>>{
|
||||||
|
self.login()?;
|
||||||
|
let arctx = Arc::new(Mutex::new(self));
|
||||||
|
let ctx = arctx.clone();
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
let mut ctx = ctx.lock().unwrap()
|
||||||
|
loop{
|
||||||
|
ctx.update_msg().await;
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
thread::join(handle).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn verify(&self) -> Result<Response, Box<dyn Error>> {
|
||||||
|
// 开始验证
|
||||||
|
let security_check_url = format!("http://{}/SSWeb/rd/j_security_check", self.ip);
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("Host", "ssweb".parse().unwrap());
|
||||||
|
headers.insert("Connection", "keep-alive".parse().unwrap());
|
||||||
|
headers.insert("Cache-Control", "max-age=0".parse().unwrap());
|
||||||
|
headers.insert("Origin", "http://ssweb".parse().unwrap());
|
||||||
|
headers.insert("DNT", "1".parse().unwrap());
|
||||||
|
headers.insert("Upgrade-Insecure-Requests", "1".parse().unwrap());
|
||||||
|
headers.insert(
|
||||||
|
"Content-Type",
|
||||||
|
"application/x-www-form-urlencoded".parse().unwrap(),
|
||||||
|
);
|
||||||
|
headers.insert("User-Agent", USER_AGENT.parse().unwrap());
|
||||||
|
headers.insert("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".parse().unwrap());
|
||||||
|
headers.insert(
|
||||||
|
"Referer",
|
||||||
|
"http://ssweb/SSWeb/rd/copy_paste.jsp".parse().unwrap(),
|
||||||
|
);
|
||||||
|
headers.insert("Accept-Encoding", "gzip, deflate".parse().unwrap());
|
||||||
|
headers.insert(
|
||||||
|
"Accept-Language",
|
||||||
|
"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
headers.insert("Cookie", self.cookies.parse().unwrap());
|
||||||
|
let contents = format!(
|
||||||
|
"j_username={}&j_password={}",
|
||||||
|
quote(&self.user_name),
|
||||||
|
quote(&self.password)
|
||||||
|
);
|
||||||
|
let resp = self
|
||||||
|
.web
|
||||||
|
.post(security_check_url)
|
||||||
|
.headers(headers)
|
||||||
|
.body(contents)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
|
fn get_cookies(response: &Response) -> String {
|
||||||
|
let mut session = String::new();
|
||||||
|
let headers: &HeaderMap = response.headers();
|
||||||
|
if let Some(header_value) = headers.get("Set-Cookie") {
|
||||||
|
if let Ok(value) = header_value.to_str() {
|
||||||
|
log::info!("Set-Cookie: {}", value);
|
||||||
|
session = value.split(';').next().unwrap().to_string();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::error!("cookies not found");
|
||||||
|
}
|
||||||
|
session
|
||||||
|
}
|
||||||
|
pub async fn login(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("User-Agent", USER_AGENT.parse().unwrap());
|
||||||
|
let url = format!("http://{}/SSWeb/rd/copy_paste.jsp", self.ip);
|
||||||
|
let response = self.web.get(url).headers(headers).send().await?;
|
||||||
|
self.cookies = ClipboardSync::get_cookies(&response);
|
||||||
|
log::info!("cookies is {}", self.cookies);
|
||||||
|
let mut resp = response.text().await?;
|
||||||
|
log::trace!("Response: {}", resp);
|
||||||
|
if resp.contains("loginForm") {
|
||||||
|
let response = self.verify().await?;
|
||||||
|
resp = response.text().await?;
|
||||||
|
log::trace!("verify Response: {}", resp);
|
||||||
|
}
|
||||||
|
if resp.contains("<title>Copy & Paste</title>") {
|
||||||
|
self.parse_msg(&resp).await;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Box::new(io::Error::new(io::ErrorKind::Other, "登录失败")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub asyn fn update_msg(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
//http://ssweb/SSWeb/rd/copy_paste.jsp?d-16544-p=1&d-16544-s=2
|
||||||
|
//d-16544-s 2:时间从靠近现在开始排序 1:时间从最早开始排序
|
||||||
|
//d-16544-o mesage排序,不要设置
|
||||||
|
//d-16544-p=1 页码
|
||||||
|
let url = format!("http://{}/SSWeb/rd/copy_paste.jsp?d-16544-p=1&d-16544-s=2", self.ip);
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("Host", "ssweb".parse().unwrap());
|
||||||
|
headers.insert("Connection", "keep-alive".parse().unwrap());
|
||||||
|
headers.insert("Cache-Control", "max-age=0".parse().unwrap());
|
||||||
|
headers.insert("DNT", "1".parse().unwrap());
|
||||||
|
headers.insert("Upgrade-Insecure-Requests", "1".parse().unwrap());
|
||||||
|
headers.insert("User-Agent", USER_AGENT.parse().unwrap());
|
||||||
|
headers.insert("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9".parse().unwrap());
|
||||||
|
headers.insert("Accept-Encoding", "gzip, deflate".parse().unwrap());
|
||||||
|
headers.insert("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6".parse().unwrap());
|
||||||
|
let response = self.web.get(url).headers(headers).send().await?;
|
||||||
|
let resp = response.text().await?;
|
||||||
|
self.parse_msg(&resp).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn parse_msg(&mut self, html: &str) -> Result<ClipboardMsgs, Box<dyn Error>> {
|
||||||
|
// log::info!("html: {}", html);
|
||||||
|
let document = Html::parse_document(html);
|
||||||
|
let selector = Selector::parse("code").unwrap();
|
||||||
|
for element in document.select(&selector) {
|
||||||
|
//let text = element.text().collect::<Vec<_>>().concat();
|
||||||
|
let text = element.text().collect::<String>();
|
||||||
|
log::info!("Found: [{}]", text);
|
||||||
|
if text[0] == '@' && text[6] == '@' {
|
||||||
|
items = text.split('@').map(|x| x.trim()).collect::<Vec<_>>();
|
||||||
|
index = items.next();
|
||||||
|
index = items.next();
|
||||||
|
}
|
||||||
|
self.clip.set(&text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(ClipboardMsgs { msgs: vec![] })
|
||||||
|
}
|
||||||
|
}
|
45
src/main.rs
Normal file
45
src/main.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
extern crate log;
|
||||||
|
use clipboard_sync::ClipboardSync;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use trust_dns_resolver::{
|
||||||
|
config::{ResolverConfig, ResolverOpts},
|
||||||
|
Resolver,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
env_logger::init();
|
||||||
|
// // 创建自定义 DNS 解析器
|
||||||
|
// let resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();
|
||||||
|
|
||||||
|
// // 要解析的域名
|
||||||
|
// let response = resolver.lookup_ip("www.baidu.com");
|
||||||
|
// match response {
|
||||||
|
// Ok(response) => {
|
||||||
|
// for ip in response {
|
||||||
|
// match ip {
|
||||||
|
// IpAddr::V4(v4) => println!("IPv4: {}", v4),
|
||||||
|
// IpAddr::V6(v6) => println!("IPv6: {}", v6),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Err(e) => {
|
||||||
|
// println!("Error: {}", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
let mut ins = ClipboardSync::new("172.19.36.79", "ekko.bao", "qwer12345;");
|
||||||
|
match ins.login().await {
|
||||||
|
Ok(()) => log::info!("登录成功"),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("登录失败: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获取 Cookies
|
||||||
|
//if let Some(cookies) = response.headers().get(COOKIE) {
|
||||||
|
// println!("Cookies: {:?}", cookies);
|
||||||
|
//} else {
|
||||||
|
// println!("No cookies found.");
|
||||||
|
//}
|
||||||
|
Ok(())
|
||||||
|
}
|
21
src/wclip/mod.rs
Normal file
21
src/wclip/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use arboard::Clipboard;
|
||||||
|
|
||||||
|
pub struct Wclip {
|
||||||
|
clipboard: Clipboard,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Wclip {
|
||||||
|
pub fn new() -> Wclip {
|
||||||
|
Wclip {
|
||||||
|
clipboard: Clipboard::new().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, text: &str) {
|
||||||
|
self.clipboard.set_text(text).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&mut self) -> String {
|
||||||
|
self.clipboard.get_text().unwrap()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user