267 lines
No EOL
5 KiB
Markdown
267 lines
No EOL
5 KiB
Markdown
padloc To Keepaas
|
|
|
|
`app.js`
|
|
```js
|
|
const fs =require('fs')
|
|
|
|
const {getRecords} = require('./helpers')
|
|
|
|
const filename= 'My_Vault_2024-05-13.csv'
|
|
// const filename= 'test.csv'
|
|
|
|
|
|
|
|
|
|
const outputDataFile = "output.xml"
|
|
|
|
let outputData=""
|
|
|
|
outputData+=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<KeePassFile>
|
|
<Meta/>
|
|
<Root>
|
|
<Group>
|
|
<Name>Root</Name>
|
|
<Notes/>
|
|
<IconID>48</IconID>
|
|
<Times/>
|
|
<IsExpanded>True</IsExpanded>
|
|
<DefaultAutoTypeSequence/>
|
|
<EnableAutoType>null</EnableAutoType>
|
|
<EnableSearching>null</EnableSearching>
|
|
<Group>
|
|
<Name>padloc</Name>
|
|
<Notes>containing prev padloc database</Notes>
|
|
<IconID>48</IconID>
|
|
<Times/>
|
|
<IsExpanded>True</IsExpanded>
|
|
<DefaultAutoTypeSequence/>
|
|
<EnableAutoType>null</EnableAutoType>
|
|
<EnableSearching>null</EnableSearching>
|
|
`
|
|
|
|
|
|
const records = getRecords(filename)
|
|
|
|
// function to map names of keys to match that of keepaas ones
|
|
const mapObjects=(obj)=>{
|
|
|
|
const newObj={}
|
|
for(let key of Object.keys(obj)){
|
|
|
|
if(obj[key].length===0){
|
|
continue;
|
|
}
|
|
|
|
// console.log('key to be mapped: ',key, ' value: ', obj[key])
|
|
|
|
switch(key){
|
|
case 'name': newObj['Title']=obj['name']; break;
|
|
case 'tags' : newObj['Tags']= obj['tags']; break;
|
|
case 'Username' : newObj['UserName'] = obj['Username']; break;
|
|
case 'Email Address' : newObj['Email'] = obj[key]; break;
|
|
case 'Plain Text' : newObj['Notes'] = obj[key]; break;
|
|
case 'Name' : newObj['UserName'] = obj[key]; break;
|
|
default : newObj[key] = obj[key]
|
|
}
|
|
}
|
|
|
|
// console.log('newObj: ',newObj)
|
|
|
|
return newObj;
|
|
}
|
|
|
|
// function to add escape sequqnce for reserved characters in xml
|
|
const mapValueForXML=(str)=>{
|
|
let newStr= str.replace(/"/g,'')
|
|
newStr = newStr.replace(/&/g,'&')
|
|
newStr = newStr.replace(/</g,'<')
|
|
newStr = newStr.replace(/>/g,'>')
|
|
newStr = newStr.replace(/"/g,'"')
|
|
newStr = newStr.replace(/'/g,''')
|
|
|
|
return newStr
|
|
|
|
}
|
|
|
|
for(let record of records){
|
|
const tags= record.tags.replace(/"/g,'')
|
|
|
|
let tagsXML=''
|
|
|
|
if(tags.length===0){
|
|
tagsXML='<Tags/>'
|
|
}
|
|
else{
|
|
tagsXML=`<Tags>${tags}</Tags>`
|
|
}
|
|
|
|
outputData+=` <Entry>
|
|
<IconID>0</IconID>
|
|
<ForegroundColor/>
|
|
<BackgroundColor/>
|
|
<OverrideURL/>
|
|
${tagsXML}
|
|
<Times/>
|
|
`
|
|
|
|
const mappedRecord = mapObjects(record)
|
|
// console.log('')
|
|
for(let key in mappedRecord){
|
|
|
|
// console.log('')
|
|
|
|
if(key==='Password'){
|
|
outputData+=` <String>
|
|
<Key>${key}</Key>
|
|
<Value ProtectInMemory="True">${ mapValueForXML(mappedRecord[key]) }</Value>
|
|
</String>
|
|
`
|
|
continue
|
|
}
|
|
|
|
|
|
outputData+=` <String>
|
|
<Key>${key}</Key>
|
|
<Value>${ mapValueForXML(mappedRecord[key]) }</Value>
|
|
</String>
|
|
`
|
|
}
|
|
|
|
outputData+=` <AutoType>
|
|
<Enabled>True</Enabled>
|
|
<DataTransferObfuscation>0</DataTransferObfuscation>
|
|
<DefaultSequence/>
|
|
</AutoType>
|
|
<History/>
|
|
</Entry>
|
|
`
|
|
|
|
}
|
|
|
|
outputData+=` </Group>
|
|
</Group>
|
|
</Root>
|
|
</KeePassFile>`
|
|
|
|
fs.writeFileSync(outputDataFile,outputData)
|
|
|
|
|
|
```
|
|
|
|
|
|
`helpers.js`
|
|
```js
|
|
const fs =require('fs')
|
|
|
|
const getRecords=(filename)=>{
|
|
const data =fs.readFileSync(filename,{encoding : 'utf8'})
|
|
|
|
// normal, quotes
|
|
let state="normal"
|
|
|
|
|
|
|
|
const lines= data.split('\n')
|
|
|
|
// console.log('lines: ',lines)
|
|
|
|
// extracting headings and also removing last character ie \r from the line
|
|
let headings= lines[0].slice(0,lines[0].length-1).split(',')
|
|
|
|
console.log('headings: ',headings)
|
|
|
|
let valuei=0
|
|
let str=``
|
|
|
|
const parseLine=(line,obj)=>{
|
|
|
|
|
|
// parsing character by character
|
|
for(let i=0;i<line.length;i++){
|
|
// comma found in normal state
|
|
|
|
if(state==="normal"&& line[i]===','){
|
|
|
|
obj[headings[valuei]]=str
|
|
// resetting buffer for next value
|
|
str=``
|
|
// moving to next field index
|
|
valuei++
|
|
}
|
|
|
|
else if(state==="normal" && line[i]==='"'){
|
|
state="quotes"
|
|
str+=line[i]
|
|
}
|
|
|
|
else if(state==="quotes" && line[i]==='"' ){
|
|
state="normal"
|
|
str+=line[i]
|
|
}
|
|
else{
|
|
str+=line[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const records=[]
|
|
|
|
let obj={}
|
|
|
|
for(let i=1;i < lines.length;i++){
|
|
|
|
// const line=lines[i].slice(0,lines[i].length-1)
|
|
|
|
// removing `\r` from every record
|
|
const line=lines[i].replace('\r','')
|
|
|
|
parseLine(line,obj)
|
|
|
|
// if at end of line, state is normal then it means current record
|
|
// ends so store last field in object and reset values, pushing record in array
|
|
if(state==='normal'){
|
|
obj[headings[valuei]]=str
|
|
|
|
records.push(obj)
|
|
// resetting buffer for next value
|
|
str=``
|
|
// moving to next field index
|
|
valuei=0
|
|
|
|
obj={}
|
|
}
|
|
// if it in quotes then add newline character to current field
|
|
else{
|
|
str+='\n'
|
|
}
|
|
|
|
// const commaSeparateArray= lines[i].split(',')
|
|
// obj['name']= commaSeparateArray[0]
|
|
// obj['tags']= commaSeparateArray[1]
|
|
// obj['Username']=commaSeparateArray[2]
|
|
// obj['Password']=commaSeparateArray[3]
|
|
// obj['URL']=commaSeparateArray[4]
|
|
// obj['Email Address']=commaSeparateArray[]
|
|
|
|
// const nameRegex= /^(.*),.*/
|
|
// const tagsRegex = /^.*,("?.*"?),.*/
|
|
|
|
|
|
}
|
|
|
|
console.log('records: ',records)
|
|
|
|
return records
|
|
|
|
|
|
}
|
|
|
|
module.exports= {getRecords}
|
|
|
|
|
|
``` |