I wrote a simple program to encode a local text file with password and decode it back. There is one text file and it is either encoded with a password or is in plain text.
I had a version in Python for this, but nim compiles to an executable, so I gave it a try.
I'm not perfectly happy with command line argument handling, as well as with some repeated code in case statement, but maybe there are other things to improve too.
import os
import system
import strutils
import terminal
import xxtea
const FILENAME = "passwords.txt"
const USAGE = """Encrypt and decrypt a file using a password.
Usage:
vault open [file]
vault close [file]
Default file:
passwords.txt
WARNING: this program may overwrite or delete file content without
a possibilty of recovery. Passwords cannot be recovered. Information
can be destroyed by repeated attempts of encryption/decryption. Use
at you own risk.
"""
proc getpass(message: string = "Password: "): string =
return terminal.readPasswordFromStdin(message)
proc getpass2(): string =
let key = getpass()
let key2 = getpass("Repeat password: ")
if key == key2:
return key
else:
quitWithMessage("Passwords do not match")
proc write(content: string): void =
writeFile(filepath(), content)
proc notify(message: string): void =
echo message, " ", filepath()
# cli args helpers
proc filepath(): string =
try:
return paramStr(2)
except IndexError:
return FILENAME
proc command(): string =
try:
return paramStr(1).toLowerAscii()
except IndexError:
quitWithMessage(USAGE)
# flow control
proc quitWithMessage(message: string): void =
echo message
quit(1)
# main
if command() notin ["open", "close", "help"]:
quitWithMessage(USAGE)
let existingContent = readFile(filepath())
case command()
of "open":
let key = getpass()
let newContent = xxtea.decrypt(existingContent, key)
write(newContent)
notify("Decoded")
of "close":
let key = getpass2()
let newContent = xxtea.encrypt(existingContent, key)
write(newContent)
notify("Encoded")
of "help":
quitWithMessage(USAGE)