Skip to content

Instantly share code, notes, and snippets.

@nikspyratos
Created November 26, 2023 07:20
Show Gist options
  • Save nikspyratos/bd0b5ef05a4d82d2d0425cb4be9844db to your computer and use it in GitHub Desktop.
Save nikspyratos/bd0b5ef05a4d82d2d0425cb4be9844db to your computer and use it in GitHub Desktop.
Proton Pass json export file -> KeePassXC import CSV
#!/usr/bin/env node
const fs = require('fs');
function convertProtonPassToJson(protonPassJson) {
// Parse the JSON input
const data = JSON.parse(protonPassJson);
// Define an array to hold CSV lines
let csvLines = [];
// CSV header line
csvLines.push("Group,Title,Username,Password,URL,Notes,TOTP,Icon,Last Modified,Created");
// Process each vault
Object.values(data.vaults).forEach(vault => {
// Skip the vault if its name is "Recycle Bin"
if (vault.name === "Recycle Bin") {
return;
}
// Process each item in the vault
vault.items?.forEach(item => {
const itemData = item.data.content;
const modifiedTime = item.modifyTime ? new Date(item.modifyTime * 1000).toISOString() : '';
const createdTime = item.createTime ? new Date(item.createTime * 1000).toISOString() : '';
// Escaping newlines in notes
const notesEscaped = item.data.metadata?.note.replace(/\n/g, '\\n').replace(/"/g, '\\"');
const passwordEscaped = itemData?.password?.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const line = [
`"${vault.name}"`,
`"${item.data.metadata?.name}"`,
`"${itemData?.username}"`,
`"${passwordEscaped}"`, // Using escaped password here
`"${itemData?.urls?.join(', ')}"`,
`"${notesEscaped}"`,
`"${itemData?.totpUri || ''}"`,
`"${modifiedTime}"`,
`"${createdTime}"`
].join(',');
csvLines.push(line);
});
});
// Join all lines to create CSV text
return csvLines.join('\n');
}
// Get the file path from command line arguments
const inputFilePath = process.argv[2];
const outputFilePath = process.argv[3];
if (!inputFilePath || !outputFilePath) {
console.error("Please provide an input file path and an output file path.");
process.exit(1);
}
const protonPassJson = fs.readFileSync(inputFilePath, 'utf8');
const csvData = convertProtonPassToJson(protonPassJson);
fs.writeFileSync(outputFilePath, csvData);
console.log(`CSV data written to ${outputFilePath}`);
@swdrumm
Copy link

swdrumm commented Jan 12, 2024

Nik - I couldn't get this to work (see below). Any suggestions? Thanks!

%node protonpass_to_keepassxc.js data.json out.csv

/home/swdrumm/Desktop/Proton Pass/protonpass_to_keepassxc.js:22
        vault.items?.forEach(item => {
                    ^

SyntaxError: Unexpected token '.'

@nikspyratos
Copy link
Author

@swdrumm Are you using a newer node version? I'm using optional chaining there.

Other than that can't help much - I'm not using Proton Pass anymore.

@swdrumm
Copy link

swdrumm commented Jan 12, 2024

@nikspyratos Installed node and npm from Ubuntu repo's today. node -v returns 12.22.9

@nikspyratos
Copy link
Author

@swdrumm That's definitely not the latest. Long story short Ubuntu usually pegs some or other stable-but-not-modern version of things. Look at nvm and installing latest node.

For ref, my node -v returns 18.16.0

@swdrumm
Copy link

swdrumm commented Jan 12, 2024

@nikspyratos OK, thanks. I'll upgrade node.js to a version that supports optional chaining.

@swdrumm
Copy link

swdrumm commented Jan 12, 2024

@nikspyratos Works great with the latest version of node.js
I didn't realize the Ubuntu repo version was that old. Thanks for the help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment