Skip to content
102 changes: 59 additions & 43 deletions src/handler/operation/cookie.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,40 @@
import { TYPES } from "../../common.js";

async function getCookie(tab, cookieStoreItems) {
const cookies = await chrome.cookies.getAll({ url: tabToStringUrl(tab) });
const cookieStoreItemsKeys = cookieStoreItems.map(({ key }) => key);

const matchCookies = cookies
.filter(({ name }) => cookieStoreItemsKeys.includes(name))
.map(({ name, value }) => ({ name, value, type: TYPES.COOKIE }));
const cookies = await chrome.cookies.getAll({ url: tabToStringUrl(tab), domain: cookieStoreItems.domain });

return cookieStoreItems.map((item) => {
item.value = matchCookies.find(({ name }) => name === item.key)?.value || undefined;
const cookie = cookieFinder(cookies, item.key, item.domain);

let value = cookie?.value;
if (item.subKey) {
try {
item.value = JSON.parse(item.value)[item.subKey];
value = JSON.parse(value)[item.subKey];
} catch {
item.value = undefined;
value = undefined;
}
}
return item;

return { ...item, value };
});
}

async function saveCookieValue(tab, key, subKey, value) {
async function saveCookieValue(tab, key, subKey, userDomain, value) {
const url = tabToStringUrl(tab);
const domain = tabToStringDomain(tab);
let details = await chrome.cookies.get({
name: key,
url,
});
if (details === null) {
details = { name: key };
}
const domain = getCookieDomain(userDomain, url);

let newValue = value;
const cookies = await chrome.cookies.getAll({ url, domain });
const cookie = cookieFinder(cookies, key, userDomain);

if (subKey) {
const originalValue = details.value;
if (details.value !== undefined)
try {
newValue = JSON.parse(originalValue);
} catch (e) {
newValue = {};
}
else newValue = {};

newValue[subKey] = value;
}
const cookieValue = getCookieValue(subKey, value, cookie.value);

const stringifiedValue = newValue instanceof Object ? JSON.stringify(newValue) : newValue;
cookie.value = cookieValue;
cookie.domain = domain;
cookie.name = key;

details.value = stringifiedValue;

delete details.hostOnly;
delete details.session;
delete cookie.hostOnly;
delete cookie.session;

return new Promise((resolve, reject) => {
chrome.cookies.set({ ...details, url, domain }, function (cookie) {
chrome.cookies.set({ ...cookie, url, domain: cookie.domain }, function (cookie, a, b) {
if (cookie) resolve();
else reject();
});
Expand All @@ -67,9 +46,46 @@ function tabToStringUrl(tab) {
return `${url.protocol}//${url.hostname}`;
}

function tabToStringDomain(tab) {
const url = new URL(tab.url);
return `.${url.hostname}`;
function getCookieDomain(userDomain, tabUrl) {
let sUrl = tabUrl;
if (userDomain) sUrl = `http://${userDomain}`;

const url = new URL(sUrl);
return url.hostname;
}

function cookieFinder(cookies, key, domain) {
return (
cookies.find((cookie) => {
if (key !== cookie.name) return false;
if (domain && !isDomainMatch(domain, cookie.domain)) return false;
return true;
}) || {}
);
}

function isDomainMatch(itemDomain, cookieDomain) {
return itemDomain === cookieDomain || itemDomain === cookieDomain.substring(1);
}

function getCookieValue(subKey, newValue, originalValue) {
let value;

if (subKey) {
if (originalValue !== undefined) {
try {
value = JSON.parse(originalValue);
} catch (e) {
value = {};
}
} else value = {};

value[subKey] = newValue;
} else {
value = newValue;
}

return value instanceof Object ? JSON.stringify(value) : value;
}

export { getCookie, saveCookieValue };
4 changes: 2 additions & 2 deletions src/handler/valueWriter.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ async function saveLocalValue(tab, key, subKey = "", value) {
return false;
}

async function saveCookieValue(tab, key, subKey = "", value) {
async function saveCookieValue(tab, key, subKey = "", domain, value) {
try {
return await chromeSaveCookieValue(tab, key, subKey, value);
return await chromeSaveCookieValue(tab, key, subKey, domain, value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This chromeSaveCookieValue function is getting crowded in terms of args, so probably it would be easier to use having it grouped some of these by their context - tab, {context of cookie}:

Suggested change
return await chromeSaveCookieValue(tab, key, subKey, domain, value);
return await chromeSaveCookieValue(tab, {key, subKey, domain, value});

WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, I'm strongly inclined to include typescript in the project.
Making this kind of changes is starting to get a bit scary 😅

I'm a bit resistant to make this change in this PR because by changing this, I feel like we would need to change local and session storage as well, which are out of scope for this PR.
What do you reckon if we move this change to a different issue?

} catch (e) {
console.log("🐶 ~ could not set cookie value for key " + key + " :", e);
}
Expand Down
2 changes: 1 addition & 1 deletion src/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function appManager() {
case TYPES.LOCAL:
return saveLocalValue(tab, item.key, item.subKey, value);
case TYPES.COOKIE:
return saveCookieValue(tab, item.key, item.subKey, value);
return saveCookieValue(tab, item.key, item.subKey, item.domain, value);
}

return false;
Expand Down
16 changes: 15 additions & 1 deletion src/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ function appPage({ storeSave, storeDelete, storeSet, refreshValues }) {
show(PAGES.LIST);
});

document.querySelectorAll('input[name="storage"]').forEach((input) =>
input.addEventListener("click", (e) => {
if (e.target.id === "localStorage" || e.target.id === "sessionStorage") hideDomainField();
else document.getElementById("domainField").classList.remove("display-none");
}),
);

function show(page) {
const emptyPage = document.getElementById("emptyPage");
const addKeyForm = document.getElementById("addKeyForm");
Expand Down Expand Up @@ -233,15 +240,17 @@ function appPage({ storeSave, storeDelete, storeSet, refreshValues }) {
const alias = document.getElementById("alias").value;
const key = document.getElementById("key").value;
const subKey = document.getElementById("subKey").value || undefined;
const domain = document.getElementById("domain").value || undefined;
const storageType = document.querySelector('input[name="storage"]:checked').value;

return { alias, key, subKey, type: storageType };
return { alias, key, subKey, domain, type: storageType };
}

function clearFormData() {
document.getElementById("alias").value = "";
document.getElementById("key").value = "";
document.getElementById("subKey").value = "";
document.getElementById("domain").value = "";
document.querySelector('input[name="storage"]').checked = false;
document.querySelector('input[id="sessionStorage"]').checked = true;
}
Expand All @@ -258,6 +267,11 @@ function appPage({ storeSave, storeDelete, storeSet, refreshValues }) {
form.classList.remove("was-validated");
}

function hideDomainField() {
const domainField = document.getElementById("domainField");
if (!domainField.classList.contains("display-none")) domainField.classList.add("display-none");
}

return {
show,
renderPresentationList,
Expand Down
4 changes: 4 additions & 0 deletions src/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ <h4>Key Retriever</h4>
</div>
</div>
</div>
<div id="domainField" class="form-floating mb-3 display-none">
<input id="domain" type="text" class="form-control" name="domain" />
<label for="domain" class="form-label">Domain</label>
</div>
<div class="form-floating mb-3">
<input id="key" type="text" class="form-control" name="key" required value="" />
<label for="key" class="form-label">Key <span style="color: red">*</span></label>
Expand Down
9 changes: 7 additions & 2 deletions src/view/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function newItem({ storageType, item, actions }) {
return [{ action: copyButton, visible: false }, { action: moreActionsButton }];
}

function itemFooter({ id, key, subKey }) {
function itemFooter({ id, domain, key, subKey }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: Following our design review about the badge & big values issue, we should review this component itemFooter. It's getting bigger and messy with new features.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your concern. Create a new issue where we can properly address it: #104

const footerBody = document.createElement("div");
addClassesToElement(footerBody, "flex flex-col mb-2");

Expand All @@ -55,10 +55,15 @@ function newItem({ storageType, item, actions }) {
keyDetailsArea.appendChild(keyLabel);

if (subKey) {
const subKeyLabel = newLabelWithBadge({ label: "Subkey", value: subKey || "" });
const subKeyLabel = newLabelWithBadge({ label: "Subkey", value: subKey });
keyDetailsArea.appendChild(subKeyLabel);
}

if (domain) {
const domainLabel = newLabelWithBadge({ label: "Domain", value: domain });
keyDetailsArea.appendChild(domainLabel);
}

footerBody.appendChild(keyDetailsArea);

const tokenArea = newTextArea({
Expand Down