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

Encrypt Location before saving #522

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<script defer src="scripts/save-load-states.js"></script>
<script defer src="scripts/wallpaper.js"></script>
<script defer src="scripts/clock.js"></script>
<script defer src="scripts/crypto-utils.js"></script>
<script defer src="scripts/weather.js"></script>
<script defer src="scripts/custom-text.js"></script>
<script defer src="scripts/browser-utils.js"></script>
Expand Down
92 changes: 92 additions & 0 deletions scripts/crypto-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Material You NewTab
* Copyright (c) 2023-2025 XengShi
* Licensed under the GNU General Public License v3.0 (GPL-3.0)
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

// Encryption Utilities using Web Crypto API: Functions for encrypting and decrypting data securely.

/**
* Encrypts the given data using the given key with AES-GCM encryption and returns an object containing the encrypted data and the initialization vector used.
* @param {string} data - The data to encrypt.
* @param {CryptoKey} key - The key to use for encryption.
* @returns {Promise<{ cipherText: string, iv: string }>} - A Promise that resolves with an object containing the encrypted data and the initialization vector used.
*/

async function encryptData(data, key) {
const enc = new TextEncoder();
const encodedData = enc.encode(data);
const iv = crypto.getRandomValues(new Uint8Array(16)); // Initialization vector
const algorithm = { name: "AES-GCM", iv };

const cipherText = await crypto.subtle.encrypt(algorithm, key, encodedData);
return {
cipherText: Array.from(new Uint8Array(cipherText)).map(byte => String.fromCharCode(byte)).join(''),
iv: Array.from(iv).map(byte => String.fromCharCode(byte)).join('')
};
}


/**
* Decrypts the given encrypted data using the given key and initialization vector (iv).
* @param {string} encrypted - The encrypted data to decrypt.
* @param {string} ivString - The initialization vector (iv) used for encryption.
* @param {CryptoKey} key - The key used for encryption.
* @returns {Promise<string>} - The decrypted data as a string.
*/

async function decryptData(encrypted, ivString, key) {
const dec = new TextDecoder();
const iv = new Uint8Array([...ivString].map(char => char.charCodeAt(0)));
const algorithm = { name: "AES-GCM", iv };

const buffer = Uint8Array.from([...encrypted].map(char => char.charCodeAt(0)));
const decryptedData = await crypto.subtle.decrypt(algorithm, key, buffer);
return dec.decode(decryptedData);
}


/**
* Generates a new AES-GCM encryption key with a length of 256 bits.
* The key can be used for both encryption and decryption operations.
* The generated key is extractable, allowing it to be exported.
* @returns {Promise<CryptoKey>} - A Promise that resolves to the generated CryptoKey.
*/

async function generateKey() {
return crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"]
);
}


/**
* Retrieves an AES-GCM encryption key from localStorage, generating and storing a new one if not found.
* If a key is not already stored, a new one is generated, exported, and saved in localStorage.
* The stored key is imported and returned for encryption and decryption operations.
* @returns {Promise<CryptoKey>} - A Promise that resolves to the imported CryptoKey.
*/

async function getKey() {
if (!localStorage.getItem('cryptoKey')) {
const key = await generateKey();
const exportedKey = await crypto.subtle.exportKey('raw', key);
localStorage.setItem('cryptoKey', Array.from(new Uint8Array(exportedKey)).map(byte => String.fromCharCode(byte)).join(''));
}

const importedKey = Uint8Array.from(localStorage.getItem('cryptoKey').split('').map(char => char.charCodeAt(0)));
return crypto.subtle.importKey(
'raw',
importedKey,
{ name: "AES-GCM" },
false,
["encrypt", "decrypt"]
);
}
36 changes: 18 additions & 18 deletions scripts/weather.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,22 +203,22 @@ document.addEventListener("DOMContentLoaded", async () => {

// Function to fetch GPS-based location
async function fetchGPSLocation() {
try {
const getLocationFromGPS = () => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
});
},
(error) => reject(error),
{ timeout: 4000 }
);
});
};
const getLocationFromGPS = () => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
});
},
(error) => reject(error),
{ timeout: 4000 }
);
});
};

try {
const { latitude, longitude } = await getLocationFromGPS();
return `${latitude},${longitude}`;
} catch (error) {
Expand All @@ -233,15 +233,15 @@ document.addEventListener("DOMContentLoaded", async () => {
try {
// Use GPS for dynamic location
currentUserLocation = await fetchGPSLocation();
} catch {
} catch (error) {
console.log("Failed to use GPS for location:", error);
}
}

if (!currentUserLocation) {
// Fallback to IP-based location if no manual input
const geoLocation = "https://ipinfo.io/json/";
const locationData = await fetch(geoLocation);
const ipLocation = "https://ipinfo.io/json/";
const locationData = await fetch(ipLocation);
const parsedLocation = await locationData.json();
currentUserLocation = parsedLocation.loc;
}
Expand Down