joplin-notes/joplin notion extension/Web Development/nodejs/snippets/padloc To Keepaas.md
2026-11-04 00:33:23 +05:30

5 KiB

padloc To Keepaas

app.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,'&amp;')
	newStr = newStr.replace(/</g,'&lt;')
	newStr = newStr.replace(/>/g,'&gt;')
	newStr = newStr.replace(/"/g,'&quot;')
	newStr = newStr.replace(/'/g,'&apos;')

	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

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}