password-store-extension/host/server.js

80 lines
2.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
const nativeMessage = require('chrome-native-messaging');
const childProcess = require('child_process');
const fs = require('fs/promises');
const path = require('path');
const passwds = path.join(process.env.HOME, '.password-store');
async function recurseDir(dir) {
const array = [];
const paths = await fs.readdir(dir);
const root = path.basename(dir);
for (const file of paths) {
const stat = await fs.stat(path.join(dir, file));
if (file.startsWith('.')) {
continue;
}
if (stat.isDirectory()) {
const children = await recurseDir(path.join(dir, file));
array.push(...children);
} else {
array.push(path.join(dir, file.replace('.gpg', '')));
}
}
return array;
}
async function findSiteInPasswords(siteDomain) {
const allPasswords = await recurseDir(passwds);
let sdwTLD = siteDomain.split('.');
sdwTLD = sdwTLD.slice(sdwTLD.length - 2, sdwTLD.length - 1).join('.');
return allPasswords
.map((file) => file.substring(passwds.length + 1))
.filter((item) => {
const name = item.toLowerCase();
return name.includes(siteDomain) || (sdwTLD && name.includes(sdwTLD));
});
}
async function getPassword(password) {
return new Promise((resolve, reject) => {
childProcess.exec(`pass ${password}`, (error, stdout, stderr) => {
if (stderr && stderr.length) {
return resolve(null);
}
resolve(stdout.toString().split('\n'));
});
});
}
process.stdin
.pipe(new nativeMessage.Input())
.pipe(
new nativeMessage.Transform(function (msg, push, done) {
if (msg.domain) {
findSiteInPasswords(msg.domain).then((results) => {
push({ results });
done();
});
return;
}
if (msg.getPassword) {
getPassword(msg.getPassword).then(([password, username]) => {
push({ password, username });
done();
});
return;
}
push({ hello: true });
done();
})
)
.pipe(new nativeMessage.Output())
.pipe(process.stdout);