Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions contrib/lpass-att-export.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,43 @@ fi

command -v lpass >/dev/null 2>&1 || { echo >&2 "I require lpass but it's not installed. Aborting."; exit 1; }

if [ ! -d ${outdir} ]; then
# shellcheck disable=SC2034 # ignore unused version variables
IFS='.' read -r lpass_ver_major lpass_ver_minor lpass_ver_patch lpass_ver_vcs <<< "$(lpass --version | sed 's/LastPass CLI v//')"
if [ "${lpass_ver_major}" -gt 1 ] || [ "${lpass_ver_major}" -eq 1 ] && [ "${lpass_ver_minor}" -gt 6 ]; then
path_format="%/_as%/_ag%_an"
else
path_format="%/as%/ag%an"
fi

if [ ! -d "${outdir}" ]; then
echo "${outdir} does not exist. Exiting."
exit 1
fi

if ! lpass status; then
if [ -z ${email} ]; then
if [ -z "${email}" ]; then
echo "No login data found, Please login with -l or use lpass login before."
exit 1;
fi
lpass login ${email}
lpass login "${email}"
fi

if [ -z ${id} ]; then
ids=$(lpass ls | sed -n "s/^.*id:\s*\([0-9]*\).*$/\1/p")
if [ -z "${id}" ]; then
# Get the ids of items that might have an attachment
# remove trailing carriage return if it's there
ids=$(lpass export --fields=id,attachpresent | grep ',1' | sed 's/,1\r\{0,1\}//')
else
ids=${id}
fi

for id in ${ids}; do
show=$(lpass show ${id})
show=$(lpass show "${id}")
attcount=$(echo "${show}" | grep -c "att-")
path=$(lpass show --format="%/as%/ag%an" ${id} | uniq | tail -1)
path=$(lpass show --format="${path_format}" "${id}" | uniq | tail -1)

until [ ${attcount} -lt 1 ]; do
att=`lpass show ${id} | grep att- | sed "${attcount}q;d" | tr -d :`
attid=$(echo ${att} | awk '{print $1}')
attname=$(echo ${att} | awk '{print $2}')
until [ "${attcount}" -lt 1 ]; do
# switch to read because the original way truncated filenames containing spaces
read -r attid attname <<< "$(lpass show "${id}" | grep att- | sed "${attcount}q;d" | tr -d :)"

if [[ -z ${attname} ]]; then
attname=${path#*/}
Expand All @@ -74,11 +83,11 @@ for id in ${ids}; do
out=${outdir}/${path}/${attcount}_${attname}
fi

echo ${id} - ${path} ": " ${attid} "-" ${attname} " > " ${out}
echo "${id} - ${path} : ${attid} - ${attname} > ${out}"

lpass show --attach=${attid} ${id} --quiet > "${out}"
lpass show "--attach=${attid}" "${id}" --quiet > "${out}"

let attcount-=1
(( attcount-=1 )) || true
done
done

49 changes: 32 additions & 17 deletions format.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,67 +80,76 @@ char *format_timestamp(char *timestamp, bool utc)
}

static
void append_str(struct buffer *buf, char *str, bool add_slash)
void append_str(struct buffer *buf, char *str, bool add_slash, bool make_fs_safe)
{
char *fs_parse_point = NULL;
/* can't set fs_parse_point here since the buffer might get reallocated by buffer_append_str */
size_t orignal_len = buf->len;

if (!str || !strlen(str))
return;

buffer_append_str(buf, str);
if (make_fs_safe) {
fs_parse_point = buf->bytes + orignal_len;
while ( (fs_parse_point = strpbrk(fs_parse_point, "/\r\n\t")) )
*fs_parse_point = '_';
}
if (add_slash)
buffer_append_char(buf, '/');
}

static
void format_account_item(struct buffer *buf, char fmt,
struct account *account, bool add_slash)
struct account *account, bool add_slash, bool make_fs_safe)
{
_cleanup_free_ char *name = NULL;
_cleanup_free_ char *ts = NULL;

switch (fmt) {
case 'i':
/* id */
append_str(buf, account->id, add_slash);
append_str(buf, account->id, add_slash, make_fs_safe);
break;
case 'n':
/* shortname */
append_str(buf, account->name, add_slash);
append_str(buf, account->name, add_slash, make_fs_safe);
break;
case 'N':
/* fullname */
name = get_display_fullname(account);
append_str(buf, name, add_slash);
append_str(buf, name, add_slash, make_fs_safe);
break;
case 'u':
/* username */
append_str(buf, account->username, add_slash);
append_str(buf, account->username, add_slash, make_fs_safe);
break;
case 'p':
/* password */
append_str(buf, account->password, add_slash);
append_str(buf, account->password, add_slash, make_fs_safe);
break;
case 'm':
/* mtime */
ts = format_timestamp(account->last_modified_gmt, true);
append_str(buf, ts, add_slash);
append_str(buf, ts, add_slash, make_fs_safe);
break;
case 'U':
/* last touch time */
ts = format_timestamp(account->last_touch, false);
append_str(buf, ts, add_slash);
append_str(buf, ts, add_slash, make_fs_safe);
break;
case 's':
/* sharename */
if (account->share)
append_str(buf, account->share->name, add_slash);
append_str(buf, account->share->name, add_slash, make_fs_safe);
break;
case 'g':
/* group name */
append_str(buf, account->group, add_slash);
append_str(buf, account->group, add_slash, make_fs_safe);
break;
case 'l':
/* URL */
append_str(buf, account->url, add_slash);
append_str(buf, account->url, add_slash, make_fs_safe);
break;
default:
break;
Expand All @@ -149,12 +158,12 @@ void format_account_item(struct buffer *buf, char fmt,

void format_field_item(struct buffer *buf, char fmt,
char *field_name, char *field_value,
bool add_slash)
bool add_slash, bool make_fs_safe)
{
if (fmt == 'n' && field_name) {
append_str(buf, field_name, add_slash);
append_str(buf, field_name, add_slash, make_fs_safe);
} else if (fmt == 'v' && field_value) {
append_str(buf, field_value, add_slash);
append_str(buf, field_value, add_slash, make_fs_safe);
}
}

Expand All @@ -165,6 +174,7 @@ void format_field(struct buffer *buf, const char *format_str,
const char *p = format_str;
bool in_format = false;
bool add_slash = false;
bool make_fs_safe = false;

while (*p) {
char ch = *p++;
Expand All @@ -188,6 +198,10 @@ void format_field(struct buffer *buf, const char *format_str,
/* append trailing slash, if nonempty */
add_slash = true;
continue;
case '_':
/* transform slashes to underscores in field value */
make_fs_safe = true;
continue;
case 'f':
/* field name/value */
if (!*p) {
Expand All @@ -196,7 +210,7 @@ void format_field(struct buffer *buf, const char *format_str,
break;
}
ch = *p++;
format_field_item(buf, ch, field_name, field_value, add_slash);
format_field_item(buf, ch, field_name, field_value, add_slash, make_fs_safe);
break;
case 'a':
/* account item */
Expand All @@ -206,13 +220,14 @@ void format_field(struct buffer *buf, const char *format_str,
break;
}
ch = *p++;
format_account_item(buf, ch, account, add_slash);
format_account_item(buf, ch, account, add_slash, make_fs_safe);
break;
default:
buffer_append_char(buf, '%');
buffer_append_char(buf, ch);
}
add_slash = false;
make_fs_safe = false;
in_format = false;
}
}
Expand Down
6 changes: 5 additions & 1 deletion lpass.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,11 @@ the following placeholders:
A slash can be added between the '%' and the placeholder to indicate that a
slash should be appended, only if the printed value is expanded to a non-empty
string. For example, this command will properly show the full path to
an account: `lpass ls --format="%/as%/ag%an"`.
an account: `lpass ls --format="%/as%/ag%an"`. In the same way, an underscore may
be added between the '%' and the placeholder to indicate that the value should
be made file-system-safe by replacing forward slashes, tabs, carriage returns,
and new lines with an underscore. This may be combined with the slash. For
example: `lpass show --format="%/_as%/_ag%_an"`.

Modifying
~~~~~~~~~
Expand Down