darkwing/database/browser_profile/model.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
#![allow(
non_snake_case,
reason = "sqlx query_as macro does not support FromRow trait, so we cant use renamed fields. see https://github.com/launchbadge/sqlx/issues/1372 and https://github.com/launchbadge/sqlx/issues/514"
)]
use serde::Serialize;
use sqlx::types::time::OffsetDateTime;
use sqlx::types::JsonValue;
use sqlx::FromRow;
/// Represents the operating system platform for a browser profile
#[derive(Debug, Clone, PartialEq, sqlx::types::Type, Eq, Hash)]
pub enum Platform {
/// Microsoft Windows operating system
Windows,
/// Apple macOS operating system
Macos,
/// Linux-based operating systems
Linux,
}
impl From<String> for Platform {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"windows" => Platform::Windows,
"macos" => Platform::Macos,
"linux" => Platform::Linux,
_ => panic!("Invalid platform: {}", value),
}
}
}
/// Represents the type of browser being emulated
#[derive(Debug, Clone, PartialEq, sqlx::types::Type)]
pub enum BrowserType {
/// Plain Google Chrome browser with injected scripts. Was used in the past,
/// now not supported.
Chrome,
/// Mozilla Firefox browser. Not used currently.
Firefox,
/// Apple Safari browser. Not used currently.
Safari,
/// Custom Anty browser. The only supported browser type now. Used by all
/// browser profiles.
Anty,
}
impl From<String> for BrowserType {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"chrome" => BrowserType::Chrome,
"firefox" => BrowserType::Firefox,
"safari" => BrowserType::Safari,
_ => BrowserType::Anty,
}
}
}
/// Represents the main website/platform the browser profile is configured for
#[derive(Debug, Clone, PartialEq, sqlx::types::Type, Eq, Hash, Copy)]
pub enum MainWebsite {
/// Facebook social network
Facebook,
/// VKontakte social network
Vk,
/// TikTok social media platform
Tiktok,
/// Google services
Google,
/// Cryptocurrency-related websites
Crypto,
/// No specific main website configured
Empty,
}
impl MainWebsite {
/// Returns all non-empty main websites.
///
/// Used for iterating over them for checking if we have all values for
/// corresponding main websites.
pub const fn all() -> [Self; 5] {
[
Self::Facebook,
Self::Vk,
Self::Tiktok,
Self::Google,
Self::Crypto,
]
}
}
impl From<String> for MainWebsite {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"facebook" => MainWebsite::Facebook,
"vk" => MainWebsite::Vk,
"tiktok" => MainWebsite::Tiktok,
"google" => MainWebsite::Google,
"crypto" => MainWebsite::Crypto,
_ => MainWebsite::Empty,
}
}
}
impl From<Option<String>> for MainWebsite {
fn from(value: Option<String>) -> Self {
value.map(|v| v.into()).unwrap_or(MainWebsite::Empty)
}
}
impl From<MainWebsite> for String {
fn from(value: MainWebsite) -> String {
match value {
MainWebsite::Facebook => "facebook",
MainWebsite::Vk => "vk",
MainWebsite::Tiktok => "tiktok",
MainWebsite::Google => "google",
MainWebsite::Crypto => "crypto",
MainWebsite::Empty => "",
}
.into()
}
}
impl Serialize for MainWebsite {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let str = String::from(*self);
serializer.serialize_str(&str)
}
}
/// Represents browser tabs associated with a profile
#[derive(FromRow, Debug)]
#[allow(unused)]
pub struct BrowserProfileTabs {
/// Unique identifier for the tabs record
pub id: u64,
/// ID of the browser profile these tabs belong to
pub browserProfileId: u64,
/// JSON representation of the tabs
pub tabs: JsonValue,
/// When the tabs record was created
pub created_at: Option<OffsetDateTime>,
/// When the tabs record was last updated
pub updated_at: Option<OffsetDateTime>,
}
/// Represents connection to the homepage for a browser profile
#[derive(FromRow, Debug)]
#[allow(unused)]
pub struct BrowserProfileHomepages {
/// Unique identifier for the homepage record
pub id: u64,
/// ID of the team this homepage belongs to
pub teamId: u64,
/// ID of the user who created this homepage
pub creatorId: u64,
/// ID of the browser profile
pub profileId: u64,
/// ID of the homepage
pub homepageId: u64,
/// Order/position of the homepage
pub order: i32,
/// When the homepage record was created
pub created_at: Option<OffsetDateTime>,
/// When the homepage record was last updated
pub updated_at: Option<OffsetDateTime>,
}
/// Represents a homepage configuration
#[derive(FromRow, Debug, Clone)]
#[allow(unused)]
pub struct Homepage {
/// Whether this homepage is shared with the entire team
pub sharedToEntireTeam: i8,
/// Name of the homepage
pub name: String,
/// URL of the homepage
pub url: String,
/// Main website category this homepage belongs to
pub mainWebsite: JsonValue,
/// Whether this is a global homepage
pub isGlobal: i8,
}
/// Represents a browser extension
#[derive(FromRow, Debug, Clone)]
pub struct Extension {
/// Unique identifier for the extension
pub extension_id: String,
/// URL where the extension can be downloaded/accessed
pub url: String,
/// Display name of the extension
pub name: Option<String>,
/// Type of the extension
pub r#type: String,
/// Hash of the extension file for verification
pub hash: Option<String>,
}
/// Represents a bookmark in the browser profile
#[derive(FromRow, Debug, Clone)]
#[allow(unused)]
pub struct Bookmark {
/// Name of the bookmark
pub name: String,
/// URL of the bookmark if deleted
pub deletedUrl: Option<String>,
/// Main website category this bookmark belongs to
pub mainWebsite: JsonValue,
/// Encrypted URL of the bookmark
pub urlCrypt: Option<Vec<u8>>,
/// ID of the encryption key used
pub cryptoKeyId: u32,
}
/// Represents WebGPU settings for a browser profile
#[derive(FromRow, Debug)]
#[allow(unused)]
pub struct BrowserProfileWebgpu {
/// Unique identifier for the WebGPU configuration
pub id: u64,
/// ID of the browser profile this configuration belongs to
pub browserProfileId: u64,
/// JSON representation of WebGPU settings
pub webgpu: JsonValue,
}
/// Represents a browser profile with fingerprint settings
#[derive(FromRow, Debug)]
#[allow(unused)]
pub struct BrowserProfileWithFingerprint {
/// Unique identifier for the browser profile
pub id: u64,
/// ID of the user this profile belongs to
#[sqlx(rename = "userId")]
pub user_id: i64,
/// ID of the team this profile belongs to
#[sqlx(rename = "teamId")]
pub team_id: i64,
/// Name of the browser profile
pub name: String,
/// Main website category this profile is configured for
#[sqlx(rename = "mainWebsite")]
pub main_website: String,
/// Operating system platform this profile is configured for
pub platform: String,
/// Type of the browser this profile is configured for
#[sqlx(rename = "browserType")]
pub browser_type: String,
/// ID of the proxy this profile is configured for
#[sqlx(rename = "proxyId")]
pub proxy_id: i64,
/// User-agent string for the browser profile
pub useragent: String,
/// WebRTC configuration for the browser profile
pub webrtc: String,
/// Canvas fingerprinting settings for the browser profile
pub canvas: String,
/// WebGL fingerprinting settings for the browser profile
pub webgl: String,
/// Detailed WebGL information for the browser profile
#[sqlx(rename = "webglInfo")]
pub webgl_info: String,
/// Client rectangle information for the browser profile
#[sqlx(rename = "clientRect")]
pub client_rect: String,
/// Notes for the browser profile
pub notes: String,
/// Timezone for the browser profile
pub timezone: String,
/// Locale for the browser profile
pub locale: String,
/// User-defined fields for the browser profile
#[sqlx(rename = "userFields")]
pub user_fields: String,
/// Geolocation settings for the browser profile
pub geolocation: String,
/// Do-not-track setting for the browser profile
#[sqlx(rename = "doNotTrack")]
pub do_not_track: i8,
/// Additional arguments for the browser profile
pub args: String,
/// CPU information for the browser profile
pub cpu: String,
/// Memory information for the browser profile
pub memory: String,
/// Screen information for the browser profile
pub screen: String,
/// Ports information for the browser profile
pub ports: String,
/// Tabs information for the browser profile
pub tabs: String,
/// When the browser profile was deleted
pub deleted_at: Option<OffsetDateTime>,
/// CPU architecture for the browser profile
#[sqlx(rename = "cpuArchitecture")]
pub cpu_architecture: String,
/// Operating system version for the browser profile
#[sqlx(rename = "osVersion")]
pub os_version: String,
/// Screen width for the browser profile
#[sqlx(rename = "screenWidth")]
pub screen_width: Option<i32>,
/// Screen height for the browser profile
#[sqlx(rename = "screenHeight")]
pub screen_height: Option<i32>,
/// Download speed for the browser profile
#[sqlx(rename = "connectionDownlink")]
pub connection_downlink: f64,
/// Effective type of the connection for the browser profile
#[sqlx(rename = "connectionEffectiveType")]
pub connection_effective_type: String,
/// Round-trip time for the browser profile
#[sqlx(rename = "connectionRtt")]
pub connection_rtt: u32,
/// Whether data saving is enabled for the browser profile's connection
#[sqlx(rename = "connectionSaveData")]
pub connection_save_data: i8,
/// The vendor sub-version string for the browser profile
#[sqlx(rename = "vendorSub")]
pub vendor_sub: String,
/// The product sub-version string for the browser profile
#[sqlx(rename = "productSub")]
pub product_sub: String,
/// The vendor name for the browser profile
pub vendor: String,
/// The product name for the browser profile
pub product: String,
/// The application code name for the browser profile
#[sqlx(rename = "appCodeName")]
pub app_code_name: String,
/// Information about available media devices for the browser profile
#[sqlx(rename = "mediaDevices")]
pub media_devices: JsonValue,
/// Hash of the data directory for the browser profile
#[sqlx(rename = "datadirHash")]
pub datadir_hash: Option<String>,
/// Version of the platform for the browser profile
#[sqlx(rename = "platformVersion")]
pub platform_version: String,
/// Whether the browser profile is archived (1) or not (0)
pub archived: i8,
/// Maximum WebGL2 capabilities for the browser profile
#[sqlx(rename = "webgl2Maximum")]
pub webgl2_maximum: Option<JsonValue>,
/// Optional login credentials for the browser profile
pub login: Option<String>,
/// Optional password for the browser profile
pub password: Option<String>,
/// Optional tab configuration for the browser profile
pub browser_profile_tabs: Option<String>,
/// WebGPU capabilities for the browser profile
pub webgpu: Option<JsonValue>,
/// Whether the profile name is hidden in the UI
#[sqlx(rename = "isHiddenProfileName")]
pub is_hidden_profile_name: Option<bool>,
/// When the browser profile was created
pub created_at: OffsetDateTime,
}
/// Represents the type of proxy connection that can be used for browser
/// profiles.
///
/// Basically, Socks4 and Socks5 are the same and their only difference is
/// number in name :). We use SOCKS5 connection to SOCKS4 servers and everything
/// works OK.
#[derive(Debug, Clone)]
pub enum ProxyType {
/// Standard HTTP proxy
Http,
/// HTTPS proxy with TLS encryption
Https,
/// SOCKS4 proxy protocol
Socks4,
/// SOCKS5 proxy protocol
Socks5,
/// SSH tunnel proxy connection
Ssh,
}
impl From<ProxyType> for String {
fn from(value: ProxyType) -> Self {
match value {
ProxyType::Http => "http".to_string(),
ProxyType::Https => "https".to_string(),
ProxyType::Socks4 => "socks4".to_string(),
ProxyType::Socks5 => "socks5".to_string(),
ProxyType::Ssh => "ssh".to_string(),
}
}
}
impl From<String> for ProxyType {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"http" => ProxyType::Http,
"https" => ProxyType::Https,
"socks4" => ProxyType::Socks4,
"socks5" => ProxyType::Socks5,
"ssh" => ProxyType::Ssh,
_ => panic!("Invalid proxy type: {}", value),
}
}
}
impl std::fmt::Display for ProxyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", String::from(self.clone()))
}
}
impl Serialize for ProxyType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&String::from(self.clone()))
}
}
/// Represents a proxy configuration for a browser profile
///
/// Contains both encrypted and unencrypted fields for proxy authentication and
/// connection details. The encrypted fields use a crypto key identified by
/// `cryptoKeyId` for secure storage.
#[derive(FromRow, Debug)]
#[allow(unused)]
pub struct Proxy {
/// Unique identifier for the proxy
pub id: u64,
/// Type of proxy protocol (HTTP, SOCKS5, etc..)
pub r#type: ProxyType,
/// Hostname or IP address of the proxy server
pub host: String,
/// Deleted/old port value (unencrypted)
pub deletedPort: Option<String>,
/// Deleted/old login value (unencrypted)
pub deletedLogin: String,
/// Password value (unencrypted)
pub password: String,
/// Encrypted login credentials
pub loginCrypt: Option<Vec<u8>>,
/// Encrypted password
pub passwordCrypt: Option<Vec<u8>>,
/// Encrypted port number
pub portCrypt: Option<Vec<u8>>,
/// ID of the crypto key used for encryption
pub cryptoKeyId: u32,
/// URL for changing the proxy IP (unencrypted)
pub changeIpUrl: Option<String>,
/// Encrypted URL for changing the proxy IP
pub changeIpUrlCrypt: Option<Vec<u8>>,
}
/// Represents preliminary browser profile data loaded from the database
///
/// Contains basic profile information like name and credentials, but not the
/// full profile configuration. Used as an intermediate representation for
/// local-api which uses it to prepare connection data, files, etc.
#[derive(FromRow, Debug, Clone)]
pub struct BrowserProfilePreliminary {
/// Unique identifier for the browser profile
pub id: u64,
/// Timestamp when the profile was created
pub created_at: OffsetDateTime,
/// Display name of the profile
pub name: String,
/// Main website associated with this profile
#[sqlx(rename = "mainWebsite")]
pub main_website: String,
/// Optional ID of the associated proxy configuration
#[sqlx(rename = "proxyId")]
pub proxy_id: Option<i64>,
/// Optional login credentials for the profile
pub login: Option<String>,
/// Optional password for the profile
pub password: Option<String>,
}
impl BrowserProfilePreliminary {
/// Returns a mock `BrowserProfilePreliminary` instance.
///
/// This method provides a default set of values for testing and development
/// purposes.
pub fn get_mock() -> Self {
Self {
id: 0,
created_at: OffsetDateTime::now_utc(),
name: "Test Profile".to_string(),
main_website: "".to_string(),
proxy_id: None,
login: None,
password: None,
}
}
}