Secret Management in Production
The storage and management of secrets in the screenly/chrome-extension
project are handled primarily through the use of browser storage APIs and environment variables. Here is a detailed breakdown of how secrets are stored, retrieved, and secured during production.
Environment Variables
The Docker setup utilizes an environment variable for configuring different environments. Specifically, the docker-compose.yml
file defines an environment variable used when running the webpack service:
services:
webpack:
...
environment:
- JEKYLL_ENV=development
In production, this variable can be set to something other than development
to adjust the application behavior accordingly, potentially controlling visibility or access levels for secrets.
Browser Storage API
The project leverages the browser’s storage API, namely browser.storage.sync
, for saving and accessing credentials and session data. The details of the implementation are visible in the StateMocker
class defined in src/test/spec/test-main.js
, which simulates browser storage during testing.
class StateMocker {
constructor() {
if (!window.browser) {
window.browser = {
storage: {
sync: {
set: () => {},
get: () => {},
remove: () => {},
}
}
}
}
this.fakeStorage = {};
this.nextFailure = null;
spyOn(browser.storage.sync, 'set').and.callFake(d => {
if (this.nextFailure) {
const theFailure = this.nextFailure;
this.nextFailure = null;
return Promise.reject(new Error(theFailure));
}
for (const [key, value] of Object.entries(d)) {
this.fakeStorage[key] = value;
}
console.log(this.fakeStorage);
return Promise.resolve();
});
spyOn(browser.storage.sync, 'get').and.callFake(keys => {
if (typeof keys == "string") {
return Promise.resolve({keys: this.fakeStorage[keys]});
}
if (Array.isArray(keys)) {
let r = {};
for (const key of keys) {
r[key] = this.fakeStorage[keys];
}
return Promise.resolve(r);
}
throw "Unimplemented";
});
spyOn(browser.storage.sync, 'remove').and.callFake(keys => {
if (typeof keys == "string") {
delete this.fakeStorage[keys];
return Promise.resolve();
}
if (Array.isArray(keys)) {
for (const key of keys) {
delete this.fakeStorage[key];
}
return Promise.resolve();
}
});
}
setNextFailure(aFailure) {
this.nextFailure = aFailure;
}
}
This mock simulates the behaviors of set
, get
, and remove
functions, allowing the project to interact with what would be actual stored keys and values.
Storing Credentials
In practical application, credentials are stored with care. The use of encrypted data is recommended when storing sensitive information. Inside the src/popup.html
, there is a warning regarding potential access:
<p>Warning: a determined attacker with physical access to your digital sign could extract these saved credentials for example.com and gain access to your account.</p>
It is critical to employ prudent measures around the deployment of secrets, such as ensuring that sessions are not left open and that tokens are scoped correctly.
Dockerfile for Dependency Management
The Dockerfile ensures that all necessary packages for building and testing the application are included. Though it does not directly deal with secrets, an efficient environment allows for safer handling of such data:
FROM node:22
WORKDIR /app
RUN mkdir -p /output
RUN chmod -R 777 /output
RUN apt-get update --fix-missing \
&& apt-get install -y \
ca-certificates \
fonts-liberation \
gconf-service \
...
libxtst6
The installation of necessary dependencies ensures a stable environment for the application while mitigating the risks associated with unverified external dependencies.
Summary
Through the combination of environment variables, the browser’s storage API, and careful coding practices regarding sensitive information, the screenly/chrome-extension
project lays down a solid foundation for handling production secrets. It is critical to incorporate additional security measures, such as encryption and scope restrictions, to mitigate risks associated with credential storage and access.