在网络世界中,隐私保护越来越受到重视。当访问受限的网站时,可能会考虑使用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处理器的列表及其功能:
Google Chrome使用HTML界面来显示设置、下载、扩展等页面,也为"下载"页面做了同样的事情。应用的"下载"页面是Chrome浏览器的一个"克隆",是一个存储在"storage"文件夹中的HTML页面。为了能够在应用程序中加载这个页面,定义了一个SchemeHandler,并将其命名为"chrome:"。所以当在地址栏中输入"chrome://storage/downloads.htm"时,CefSharp会询问SchemeHandler如何处理它,处理器会从存储文件夹返回请求的文件。
<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浏览器。