基于CefSharp和Tor.NET的浏览器应用开发

在网络世界中,隐私保护越来越受到重视。当访问受限的网站时,可能会考虑使用Tor网络。Tor是一个匿名通信网络,它通过分散和加密数据包来保护用户的身份和活动。然而,使用Tor浏览器可能会遇到一些不便,例如界面不友好、不支持某些插件等。为了解决这些问题,本文将介绍如何使用CefSharp和Tor.NET库开发一个更加易用的浏览器应用。

应用概述

这个浏览器应用使用CefSharp作为Web浏览器组件,并通过Tor.NET库连接到Tor网络。CefSharp是一个基于Chromium的.NET库,它允许开发者在自己的应用程序中嵌入一个功能丰富的Web浏览器。Tor.NET则是一个.NET库,用于连接和管理Tor网络。

应用界面

启动应用后,它会自动连接到Tor网络并启动HTTP代理。当Tor准备就绪时,地址栏会变成淡绿色。应用界面模仿了Google Chrome的标签式浏览器,包括“下载”按钮和“DuckDuckGo”按钮,后者可以打开一个使用.onion地址的DuckDuckGo搜索引擎。

代码解析

这个应用是一个WinForms应用程序,只有一个表单。但是代码中有一些有趣的部分,可能会对好奇的开发者有所帮助。

CefSettings settings = new CefSettings(); // 设置代理为Tor settings.CefCommandLineArgs.Add("proxy-server", "127.0.0.1:8182"); // 加载Pepper Flash播放器 settings.CefCommandLineArgs.Add("ppapi-flash-path", appPath + @"\PepperFlash\pepflashplayer.dll"); settings.RegisterScheme(new CefCustomScheme { SchemeName = SchemeHandlerFactory.SchemeName, SchemeHandlerFactory = new SchemeHandlerFactory() });

通过添加"proxy-server"命令行参数,让CefSharp组件使用Tor代理。如果想在浏览器中使用Flash,可以将Chrome安装目录下的PepperFlash文件夹复制到应用程序目录,并取消注释与PepperFlash相关的代码。但请注意,如果非常关心隐私,使用Tor时不建议使用Flash,因为Flash插件可能会绕过代理直接访问互联网。

Tor是通过调用InitializeTor函数初始化的,这个函数是从Tor.NET示例应用程序中直接复制过来的。

CefSharp处理器用于使CefSharp"行为"。以下是CefSharp处理器的列表及其功能:

  • DownloadHandler:当新的下载开始时通知应用程序,并提供正在进行的下载的进度信息。
  • KeyboardHandler:当焦点在CefSharp浏览器上时,它会"吃掉"用户按下的所有键。应用程序使用Ctrl-F4关闭活动浏览器标签,因此这个处理器有助于通知应用程序在浏览器中按下了Ctrl-F4。
  • LifeSpanHandler:CefSharp在打开弹出窗口之前调用这个处理器的OnBeforePopup函数,并告诉CefSharp在新标签中打开它,而不是在单独的窗口中。
  • MenuHandler:将Chrome浏览器中使用最多的项目添加到浏览器上下文菜单中。这个处理器就是做这个的。上下文菜单的一个有趣的额外功能是"另存为PDF"选项,这在Google Chrome中是不存在的。
  • SchemeHandler:这个处理器有助于加载以"chrome://"开头的网页。

Google Chrome使用HTML界面来显示设置、下载、扩展等页面,也为"下载"页面做了同样的事情。应用的"下载"页面是Chrome浏览器的一个"克隆",是一个存储在"storage"文件夹中的HTML页面。为了能够在应用程序中加载这个页面,定义了一个SchemeHandler,并将其命名为"chrome:"。所以当在地址栏中输入"chrome://storage/downloads.htm"时,CefSharp会询问SchemeHandler如何处理它,处理器会从存储文件夹返回请求的文件。

JavaScript代码

<script type="text/javascript"> var $container; var $template; var timer; $(document).ready(function() { $container = $("#downloads-display"); $template = $("#template"); UpdateList(); timer = setInterval(UpdateList, 500); }); function UpdateItem(item) { var $item; var id = "d" + item.Id; $item = $("#" + id); // Add item if it does not exist if ($item.length == 0) { $item = $($template[0].outerHTML); $container.prepend($item); $item.removeAttr("hidden"); $item.attr("id", id); $item.find("a.cancel").click(function() { host.cancelDownload(item.Id); }); $item.find("img.icon").attr("src", "chrome://fileicon/" + item.SuggestedFileName); var startTime = getDate(item.StartTime); $item.find("div.since").text(startTime.format("dd.MM.yyyy")); $item.find("div.date").text(startTime.format("hh:mm:ss")); if (item.SuggestedFileName != "") $item.find("span.name").text(item.SuggestedFileName); $item.find("a.src-url").attr("href", item.Url).text(item.Url); $item.find("a.cancel").removeAttr("hidden"); } var progress = ""; if (item.IsInProgress) { progress = formatBytes(item.CurrentSpeed) + "/s - " + formatBytes(item.ReceivedBytes, 2); if (item.TotalBytes > 0) progress += " of " + formatBytes(item.TotalBytes, 2); if (item.PercentComplete > 0) progress += "(" + item.PercentComplete + "%)"; } else { if (item.IsComplete) progress = "Complete"; else if (item.IsCancelled) progress = "Cancelled"; $item.find("a.cancel").attr("hidden", ""); } $item.find("span.status").text(progress); } function UpdateList() { host.getDownloads().then(function(res) { var list = JSON.parse(res); $.each(list, function(key, item) { UpdateItem(item); }); }); } </script>

当页面加载时,它设置了一个定时器,每500毫秒更新一次下载列表。

最具挑战性的部分

Google Chrome在下载页面上显示下载文件的图标。为了在应用程序中实现相同的功能,在SchemeHandler中添加了一个额外的案例:

if (uri.Host == "fileicon") { Task.Factory.StartNew(() => { using (callback) { stream = GetFileIcon(fileName, IconReader.IconSize.Large); mimeType = ResourceHandler.GetMimeType(".png"); callback.Continue(); } }); return true; }

如果在地址栏中输入"chrome://fileicon/somefile.zip",这段代码就会执行,并要求操作系统返回给定文件类型的图标,然后将其返回给CefSharp浏览器。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485