Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Safari Extension] Using declarativeNetRequest API for default redirection #81

Merged
merged 4 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions safari/Universal/Kagi Search.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@
3ED5D58F2B0DFC34009DDDAD /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = 3ED5D58D2B0DFC34009DDDAD /* _locales */; };
3ED5D5912B0DFC81009DDDAD /* images in Resources */ = {isa = PBXBuildFile; fileRef = 3ED5D5902B0DFC81009DDDAD /* images */; };
3ED5D5922B0DFC81009DDDAD /* images in Resources */ = {isa = PBXBuildFile; fileRef = 3ED5D5902B0DFC81009DDDAD /* images */; };
FE08124D2C14D36000D0899F /* rule-builder.js in Resources */ = {isa = PBXBuildFile; fileRef = FE08124C2C14D36000D0899F /* rule-builder.js */; };
FE08124E2C14D36000D0899F /* rule-builder.js in Resources */ = {isa = PBXBuildFile; fileRef = FE08124C2C14D36000D0899F /* rule-builder.js */; };
FE0812502C14D39200D0899F /* kagi-content-script.js in Resources */ = {isa = PBXBuildFile; fileRef = FE08124F2C14D39200D0899F /* kagi-content-script.js */; };
FE0812512C14D39200D0899F /* kagi-content-script.js in Resources */ = {isa = PBXBuildFile; fileRef = FE08124F2C14D39200D0899F /* kagi-content-script.js */; };
FE7FB18C2C053F2F00198663 /* content-script.js in Resources */ = {isa = PBXBuildFile; fileRef = FE7FB18B2C053F2F00198663 /* content-script.js */; };
FE7FB18D2C053F2F00198663 /* content-script.js in Resources */ = {isa = PBXBuildFile; fileRef = FE7FB18B2C053F2F00198663 /* content-script.js */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -189,6 +195,9 @@
3ED5D5902B0DFC81009DDDAD /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = images; sourceTree = "<group>"; };
C31E691D2823DD4E00B1491B /* Kagi for Safari.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Kagi for Safari.app"; sourceTree = BUILT_PRODUCTS_DIR; };
C39A9F7028588C0100E4C0A3 /* MainConfig.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = MainConfig.xcconfig; sourceTree = "<group>"; };
FE08124C2C14D36000D0899F /* rule-builder.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "rule-builder.js"; sourceTree = "<group>"; };
FE08124F2C14D39200D0899F /* kagi-content-script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "kagi-content-script.js"; sourceTree = "<group>"; };
FE7FB18B2C053F2F00198663 /* content-script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "content-script.js"; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -342,6 +351,9 @@
3ED5D58D2B0DFC34009DDDAD /* _locales */,
3ED5D5552B0DE720009DDDAD /* popup.js */,
3ED5D5562B0DE720009DDDAD /* background.js */,
FE08124C2C14D36000D0899F /* rule-builder.js */,
FE7FB18B2C053F2F00198663 /* content-script.js */,
FE08124F2C14D39200D0899F /* kagi-content-script.js */,
3ED5D55A2B0DE720009DDDAD /* popup.html */,
3ED5D55C2B0DE720009DDDAD /* popup.css */,
);
Expand Down Expand Up @@ -587,12 +599,15 @@
buildActionMask = 2147483647;
files = (
3ED5D5712B0DE720009DDDAD /* popup.css in Resources */,
FE08124D2C14D36000D0899F /* rule-builder.js in Resources */,
3E9DF5082B3E3E70005DF2C3 /* manifest.json in Resources */,
3ED5D58E2B0DFC34009DDDAD /* _locales in Resources */,
FE7FB18C2C053F2F00198663 /* content-script.js in Resources */,
3ED5D56D2B0DE720009DDDAD /* popup.html in Resources */,
3ED5D5672B0DE720009DDDAD /* background.js in Resources */,
3ED5D5912B0DFC81009DDDAD /* images in Resources */,
3ED5D5652B0DE720009DDDAD /* popup.js in Resources */,
FE0812502C14D39200D0899F /* kagi-content-script.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -601,12 +616,15 @@
buildActionMask = 2147483647;
files = (
3ED5D5722B0DE720009DDDAD /* popup.css in Resources */,
FE08124E2C14D36000D0899F /* rule-builder.js in Resources */,
3ED5D58F2B0DFC34009DDDAD /* _locales in Resources */,
3ED5D56E2B0DE720009DDDAD /* popup.html in Resources */,
FE7FB18D2C053F2F00198663 /* content-script.js in Resources */,
3E7B281A2B86D220005EB620 /* manifest.json in Resources */,
3ED5D5682B0DE720009DDDAD /* background.js in Resources */,
3ED5D5922B0DFC81009DDDAD /* images in Resources */,
3ED5D5662B0DE720009DDDAD /* popup.js in Resources */,
FE0812512C14D39200D0899F /* kagi-content-script.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
4 changes: 2 additions & 2 deletions safari/Universal/MainConfig.xcconfig
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
MARKETING_VERSION = 2.2.3
CURRENT_PROJECT_VERSION = 25 // this needs to be increased with each version change as well (not set to 1 when version is updated)
MARKETING_VERSION = 2.2.6
CURRENT_PROJECT_VERSION = 36 // this needs to be increased with each version change as well (not set to 1 when version is updated)
PRODUCT_NAME = Kagi for Safari
2 changes: 1 addition & 1 deletion safari/Universal/Shared (App)/Base.lproj/Main.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<h2>Instructions</h2>
<ol class="instructions">
<li>
<strong>Enable</strong> extension in <a class="open-preferences platform-ios" href="#">Safari Extension Settings</a><span class="open-preferences platform-mac">Safari Extension Settings</span>.
<strong>Enable</strong> extension in <a class="open-preferences platform-ios" href="#">Safari Extension Settings</a>, and <strong>Allow</strong> permissions for "kagi<img />.<img />com"<span class="open-preferences platform-mac">Safari Extension Settings</span>.
<a href="../enable_extension.png" class="screenshot platform-mac"><object type="image/svg+xml" data="../ScreenshotIcon.svg"></object></a>
<fieldset id="open-settings-button" class="platform-mac">
<button class="open-preferences">Open Safari Extension Settings</button>
Expand Down
5 changes: 1 addition & 4 deletions safari/Universal/Shared (App)/Resources/Style.css
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,10 @@ a.screenshot:hover > object {

.instruction-animation {
display: block;
width: 100vw;
width: 70vw;
height: auto;
max-width: 450px; /* this is slightly larger than the widest iPhone in portrait mode. we want 100% width in portrait on iPhone, otherwise this maximum keeps things looking good. */
border: solid 2px #ccc;
border-left: none;
border-right: none;

}

hr {
Expand Down
57 changes: 35 additions & 22 deletions safari/Universal/Shared (Extension)/Resources/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,6 @@ const yahooUrls = {
"search.yahoo.com": "p"
};
const builtInEngines = Object.assign({}, googleUrls, yandexUrls, ddgUrls, bingUrls, baiduUrls, sogouUrls, ecosiaUrls, yahooUrls);
const domainMap = {
"Google": ["google.com.au", "google.md", "google.ru", "google.me", "google.com.qa", "google.com.gt", "google.se", "google.tm", "google.vg", "google.it", "google.cat", "google.com.ru", "google.com.gr", "google.ee", "google.cd", "google.sk", "google.com.ly", "google.hn", "google.co.jp", "google.ad", "google.com.sg", "google.ie", "google.co.vi", "google.kg", "google.com.kh", "google.co.ck", "google.is", "google.tt", "google.vu", "google.bg", "google.ch", "google.com.sa", "google.tn", "google.pl", "google.ro", "google.gm", "google.tl", "google.mg", "google.dk", "google.com.bo", "google.je", "google.com.kw", "google.dz", "google.ga", "google.com.gh", "google.lt", "google.com.ag", "google.ps", "google.com.vc", "google.com.pr", "google.co.cr", "google.pn", "google.com.tr", "google.sn", "google.tg", "google.gg", "google.gr", "google.com.mt", "google.nu", "google.cm", "google.lk", "google.co.mz", "google.cv", "google.sm", "google.no", "google.al", "google.bi", "google.com.af", "google.sr", "google.jo", "google.sh", "google.co.uk", "google.co.bw", "google.dm", "google.at", "google.co.ug", "google.dj", "google.si", "google.com.pg", "google.com.tj", "google.co.za", "google.nl", "google.sc", "google.ae", "google.mv", "google.ne", "google.gy", "google.com.sl", "google.co.in", "google.com.bn", "google.ht", "google.com.ua", "google.com.my", "google.co.kr", "google.com", "google.by", "google.com.cu", "google.com.lb", "google.co.nz", "google.mu", "google.com.om", "google.as", "google.com.pe", "google.mk", "google.td", "google.es", "google.az", "google.com.hk", "google.com.do", "google.bt", "google.am", "google.fm", "google.com.mx", "google.fi", "google.com.bz", "google.st", "google.com.vn", "google.rs", "google.bs", "google.cn", "google.com.pa", "google.com.sb", "google.lv", "google.co.uz", "google.co.hu", "google.co.ve", "google.co.zw", "google.com.ai", "google.com.co", "google.ci", "google.com.uy", "google.cl", "google.mw", "google.cz", "google.co.il", "google.co.th", "google.be", "google.hr", "google.fr", "google.im", "google.com.ec", "google.cg", "google.iq", "google.com.np", "google.gl", "google.co.ke", "google.co.id", "google.ml", "google.ms", "google.com.ni", "google.mn", "google.ki", "google.lu", "google.hu", "google.rw", "google.co.ma", "google.com.tw", "google.co.ls", "google.com.et", "google.li", "google.com.br", "google.bj", "google.com.py", "google.co.tz", "google.ba", "google.co.ao", "google.bf", "google.com.ph", "google.com.sv", "google.com.bd", "google.com.mm", "google.la", "google.ws", "google.com.fj", "google.co.zm", "google.cf", "google.nr", "google.to", "google.com.jm", "google.com.ar", "google.com.gi", "google.ca", "google.kz", "google.com.cy", "google.de", "google.com.na", "google.com.pk", "google.pt", "google.ge", "google.so", "google.com.bh", "google.com.eg", "google.com.ng"],
"DuckDuckGo": ["duckduckgo.com", "duckduckgo.pl", "duckduckgo.jp", "duckduckgo.co", "duckduckco.de", "duckduckgo.ca", "duckduckgo.co.uk", "duckduckgo.com.mx", "duckduckgo.com.tw", "duckduckgo.dk", "duckduckgo.in", "duckduckgo.ke", "duckduckgo.mx", "duckduckgo.nl", "duckduckgo.org", "duckduckgo.sg", "duckduckgo.uk", "duckgo.com", "ddg.co", "ddg.gg", "duck.co", "duck.com"],
"Yahoo": ["search.yahoo.com"],
"Ecosia": ["ecosia.org"],
"Bing": ["bing.com"],
"Sogou": ["m.so.com", "so.com", "sogou.com", "m.sogou.com"],
"Baidu": ["baidu.com", "m.baidu.com"],
"Yandex": ["yandex.ru", "yandex.org", "yandex.net", "yandex.net.ru", "yandex.com.ru", "yandex.ua", "yandex.com.ua", "yandex.by", "yandex.eu", "yandex.ee", "yandex.lt", "yandex.lv", "yandex.md", "yandex.uz", "yandex.mx", "yandex.do", "yandex.tm", "yandex.de", "yandex.ie", "yandex.in", "yandex.qa", "yandex.so", "yandex.nu", "yandex.tj", "yandex.dk", "yandex.es", "yandex.pt", "yandex.pl", "yandex.lu", "yandex.it", "yandex.az", "yandex.ro", "yandex.rs", "yandex.sk", "yandex.no", "ya.ru", "yandex.com", "yandex.asia", "yandex.mobi"]
};
function domainKeyForHost(knownHost) {
let domainKeys = Object.keys(domainMap);
for (let i=0; i<domainKeys.length; i++) {
Expand Down Expand Up @@ -364,6 +354,7 @@ function rewriteQueryURL(a, b) {
}
var tk = 0;
function checkForSearch(a) {
console.log("webNavigation redirect");
if (!flagFetchedPreferences) {
console.log("[checkForSearch] Search query started before preferences were fetched");
getPreferencesFromStorage(function(){
Expand Down Expand Up @@ -493,17 +484,39 @@ getPreferencesFromStorage(function(){
console.log("Finished fetching preferences on startup");
});

function messageReceived(data, sender) {
let updatedKagiPrivateSessionLink = data["updatedKagiPrivateSessionLink"];
let updatedKagiEngineToRedirect = data["updatedKagiEngineToRedirect"];
if (stringIsValid(updatedKagiPrivateSessionLink) || stringIsValid(updatedKagiEngineToRedirect)) {
// FIXME: Decide whether to send the session link and engine choice through storage or through the message itself. Right now we're doing both.
getPreferencesFromStorage(function(){
console.log("Finished fetching preferences after receiving an update message from popup.js");
});
return Promise.resolve(true);
} else {
return false;
}
async function messageReceived(data, sender) {
let updatedKagiPrivateSessionLink = data["updatedKagiPrivateSessionLink"];
let updatedKagiEngineToRedirect = data["updatedKagiEngineToRedirect"];
if (stringIsValid(updatedKagiPrivateSessionLink) || stringIsValid(updatedKagiEngineToRedirect)) {
if (shouldUseDNR()) {
const prefs = await browser.storage.local.get(["kagiPrivateSessionLink","kagiEngineToRedirect"]);

if (stringIsValid(updatedKagiPrivateSessionLink)) {
if (updatedKagiPrivateSessionLink == prefs.kagiPrivateSessionLink) {
return;
}
}

currentEngine = prefs.kagiEngineToRedirect;
privateSessionLink = prefs.kagiPrivateSessionLink;

if (typeof currentEngine === "undefined") {
currentEngine = "All";
}

if (typeof privateSessionLink === "undefined") {
privateSessionLink = null;
}

console.log("Updating rules with preps", { currentEngine, privateSessionLink });
await synchronizeRules(currentEngine, privateSessionLink);
}
return Promise.resolve(true);
} else {
return false;
}
}

browser.runtime.onMessage.addListener(messageReceived);

(async () => await initialize())();
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
browser.runtime.sendMessage({ greeting: "kagi" }).then((response) => {
console.log("Received response: ", response);
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log("Received request: ", request);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
var scrapedToken = "";
try {
let openSearchHrefSplit = document.querySelector("link[rel=search]").getAttribute("href").split(".xml/");
if (openSearchHrefSplit.length == 2) {
scrapedToken = openSearchHrefSplit[1];
}
} catch (e) {
console.error(`[Extension] Error finding Kagi session token on page: ${e.message}`);
}

// Fetch current session token
fetch("https://kagi.com/user/session", {
credentials: "include"
})
.then((response) => response.json())
.then((json) => {
if (json == null) {
return;
}
var token = json["id"];
if (scrapedToken.length > 0) {
token = scrapedToken;
}

if (typeof token == "string" && token.length > 0) {
var tokenLink = "https://kagi.com/search?token=" + token
browser.storage.local.set({ "kagiPrivateSessionLink": tokenLink })
.then((result) => {
browser.runtime.sendMessage({
"updatedKagiPrivateSessionLink": tokenLink
});
if (location.href.indexOf("https://kagi.com/signin") == 0) {
let kagi_sse_replay = localStorage.getItem("kagi_sse_replay")
if (typeof kagi_sse_replay !== "undefined" && kagi_sse_replay != null) {
let values = JSON.parse(kagi_sse_replay);
if (typeof values !== "undefined" && values != null) {
let keys = Object.keys(values);
if (keys.length > 0) {
let searchString = keys[0];
if (searchString.indexOf("search?q=") == 0) {
window.location = "http://kagi.com/" + searchString + "&token=" + token;
}
}
}
}
}
})
}
})
.catch((e) => console.error(`[Extension] Error fetching Kagi session token through API: ${e.message}`));



13 changes: 12 additions & 1 deletion safari/Universal/Shared (Extension)/Resources/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ fieldset {
input, select, p, label, button {
width: 100%;
}
input[type="checkbox"], label[checkbox] {
width: auto;
}
label[checkbox] {
display: contents;
}
fieldset input, fieldset select {
font-size: 0.9em;
font-weight: 300;
Expand Down Expand Up @@ -177,4 +183,9 @@ li.displayChildren:has(.showMore) > *:not(h4) { display: inherit; }
#instructions>li:not(:first-child) {
border-color: var(--borderColorLight);
}
}
}

body:not(.setupPermissionsGranted) .setupPermissionsGranted,
body.setupPermissionsGranted .noSetupPermissions {
display: none !important;
}
15 changes: 15 additions & 0 deletions safari/Universal/Shared (Extension)/Resources/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<!-- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">-->
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src *; img-src 'self' data:">-->
<link rel="stylesheet" href="popup.css">
<script src="rule-builder.js"></script>
<script type="module" src="popup.js" defer></script>
</head>
<body>
Expand Down Expand Up @@ -38,6 +39,20 @@ <h4>Engine to redirect</h4>
<option value="Yandex" name="Yandex">Yandex</option>
</select>
</fieldset>
</li>
<li id="setup" class="noSetupPermissions">
<h4 style="color: #FFCC02;"><img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLUdlbmVyYXRvcjogQXBwbGUgTmF0aXZlIENvcmVTVkcgMjMyLjUtLT4KPCFET0NUWVBFIHN2ZwpQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIgogICAgICAgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYuNzgxMiIgaGVpZ2h0PSIxNC45Mjk3Ij4KIDxnPgogIDxyZWN0IGhlaWdodD0iMTQuOTI5NyIgb3BhY2l0eT0iMCIgd2lkdGg9IjE2Ljc4MTIiIHg9IjAiIHk9IjAiLz4KICA8cGF0aCBkPSJNMi4xMzI4MSAxNC44NDM4TDE0LjI0MjIgMTQuODQzOEMxNS41NzAzIDE0Ljg0MzggMTYuMzc1IDEzLjkyMTkgMTYuMzc1IDEyLjcyNjZDMTYuMzc1IDEyLjM1OTQgMTYuMjY1NiAxMS45NzY2IDE2LjA3MDMgMTEuNjMyOEwxMC4wMDc4IDEuMDcwMzFDOS42MDE1NiAwLjM1OTM3NSA4LjkwNjI1IDAgOC4xODc1IDBDNy40Njg3NSAwIDYuNzY1NjIgMC4zNTkzNzUgNi4zNjcxOSAxLjA3MDMxTDAuMzA0Njg4IDExLjYzMjhDMC4wOTM3NSAxMS45ODQ0IDAgMTIuMzU5NCAwIDEyLjcyNjZDMCAxMy45MjE5IDAuODA0Njg4IDE0Ljg0MzggMi4xMzI4MSAxNC44NDM4WiIgZmlsbD0iI2ZmY2MwMCIvPgogIDxwYXRoIGQ9Ik04LjE5NTMxIDkuNjI1QzcuNzg5MDYgOS42MjUgNy41NjI1IDkuMzkwNjIgNy41NTQ2OSA4Ljk3NjU2TDcuNDUzMTIgNC43MjY1NkM3LjQ0NTMxIDQuMzEyNSA3Ljc1IDQuMDE1NjIgOC4xODc1IDQuMDE1NjJDOC42MDkzOCA0LjAxNTYyIDguOTM3NSA0LjMyMDMxIDguOTI5NjkgNC43MzQzOEw4LjgxMjUgOC45NzY1NkM4LjgwNDY5IDkuMzk4NDQgOC41NzgxMiA5LjYyNSA4LjE5NTMxIDkuNjI1Wk04LjE5NTMxIDEyLjI0MjJDNy43MjY1NiAxMi4yNDIyIDcuMzIwMzEgMTEuODY3MiA3LjMyMDMxIDExLjQwNjJDNy4zMjAzMSAxMC45Mzc1IDcuNzE4NzUgMTAuNTYyNSA4LjE5NTMxIDEwLjU2MjVDOC42NjQwNiAxMC41NjI1IDkuMDYyNSAxMC45Mjk3IDkuMDYyNSAxMS40MDYyQzkuMDYyNSAxMS44NzUgOC42NTYyNSAxMi4yNDIyIDguMTk1MzEgMTIuMjQyMloiIGZpbGw9IiNmZmZmZmYiLz4KIDwvZz4KPC9zdmc+Cg==" style="height: 14px; margin-right:4px" />Setup Pending</h4>
<p>To set up Kagi redirects for search engines, grant setup permissions, or run a search in Safari's location bar, then reopen the extension to enable redirects to Kagi.
</p>

<fieldset>
<input type="button" id="setup-permissions-button" value="Grant setup permissions" />
</fieldset>

</li>
<li id="dnr-status-wrapper">
<input type="checkbox" id="is-dnr-enabled" name="is-dnr-enabled" value="false" checked>
<label checkbox="" for="is-dnr-enabled">Use fast redirect method. Should work for most users. If you experience issues, uncheck this option.</label>
</li>
<li id="private-browsing">
<h4>Private browsing</h4>
Expand Down
Loading
Loading