Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36276665
pass.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
9 KB
Subscribers
None
pass.cpp
View Options
#include
"pass.h"
#include
"qtpasssettings.h"
#include
"util.h"
#ifdef QT_DEBUG
#include
"debughelper.h"
#endif
using
namespace
std
;
using
namespace
Enums
;
/**
* @brief Pass::Pass wrapper for using either pass or the pass imitation
*/
Pass
::
Pass
()
:
wrapperRunning
(
false
),
env
(
QProcess
::
systemEnvironment
())
{
connect
(
&
exec
,
static_cast
<
void
(
Executor
::*
)(
int
,
int
,
const
QString
&
,
const
QString
&
)
>
(
&
Executor
::
finished
),
this
,
&
Pass
::
finished
);
// TODO(bezet): stop using process
// connect(&process, SIGNAL(error(QProcess::ProcessError)), this,
// SIGNAL(error(QProcess::ProcessError)));
connect
(
&
exec
,
&
Executor
::
starting
,
this
,
&
Pass
::
startingExecuteWrapper
);
}
void
Pass
::
executeWrapper
(
PROCESS
id
,
const
QString
&
app
,
const
QStringList
&
args
,
bool
readStdout
,
bool
readStderr
)
{
executeWrapper
(
id
,
app
,
args
,
QString
(),
readStdout
,
readStderr
);
}
void
Pass
::
executeWrapper
(
PROCESS
id
,
const
QString
&
app
,
const
QStringList
&
args
,
QString
input
,
bool
readStdout
,
bool
readStderr
)
{
#ifdef QT_DEBUG
dbg
()
<<
app
<<
args
;
#endif
exec
.
execute
(
id
,
QtPassSettings
::
getPassStore
(),
app
,
args
,
input
,
readStdout
,
readStderr
);
}
void
Pass
::
init
()
{
#ifdef __APPLE__
// If it exists, add the gpgtools to PATH
if
(
QFile
(
"/usr/local/MacGPG2/bin"
).
exists
())
env
.
replaceInStrings
(
"PATH="
,
"PATH=/usr/local/MacGPG2/bin:"
);
// Add missing /usr/local/bin
if
(
env
.
filter
(
"/usr/local/bin"
).
isEmpty
())
env
.
replaceInStrings
(
"PATH="
,
"PATH=/usr/local/bin:"
);
#endif
if
(
!
QtPassSettings
::
getGpgHome
().
isEmpty
())
{
QDir
absHome
(
QtPassSettings
::
getGpgHome
());
absHome
.
makeAbsolute
();
env
<<
"GNUPGHOME="
+
absHome
.
path
();
}
}
/**
* @brief Pass::Generate use either pwgen or internal password
* generator
* @param length of the desired password
* @param charset to use for generation
* @return the password
*/
QString
Pass
::
Generate_b
(
unsigned
int
length
,
const
QString
&
charset
)
{
QString
passwd
;
if
(
QtPassSettings
::
isUsePwgen
())
{
// --secure goes first as it overrides --no-* otherwise
QStringList
args
;
args
.
append
(
"-1"
);
if
(
QtPassSettings
::
isLessRandom
())
args
.
append
(
"--secure"
);
args
.
append
(
QtPassSettings
::
isAvoidCapitals
()
?
"--no-capitalize"
:
"--capitalize"
);
args
.
append
(
QtPassSettings
::
isAvoidNumbers
()
?
"--no-numerals"
:
"--numerals"
);
if
(
QtPassSettings
::
isUseSymbols
())
args
.
append
(
"--symbols"
);
args
.
append
(
QString
::
number
(
length
));
QString
p_out
;
// TODO(bezet): try-catch here(2 statuses to merge o_O)
if
(
exec
.
executeBlocking
(
QtPassSettings
::
getPwgenExecutable
(),
args
,
&
passwd
)
==
0
)
passwd
.
remove
(
QRegExp
(
"[
\\
n
\\
r]"
));
else
{
passwd
.
clear
();
qDebug
()
<<
__FILE__
<<
":"
<<
__LINE__
<<
"
\t
"
<<
"pwgen fail"
;
// TODO(bezet): emit critical ?
}
}
else
{
if
(
charset
.
length
()
>
0
)
{
passwd
=
generateRandomPassword
(
charset
,
length
);
}
else
{
emit
critical
(
tr
(
"No characters chosen"
),
tr
(
"Can't generate password, there are no characters to choose from "
"set in the configuration!"
));
}
}
return
passwd
;
}
/**
* @brief Pass::GenerateGPGKeys internal gpg keypair generator . .
* @param batch GnuPG style configuration string
*/
void
Pass
::
GenerateGPGKeys
(
QString
batch
)
{
executeWrapper
(
GPG_GENKEYS
,
QtPassSettings
::
getGpgExecutable
(),
{
"--gen-key"
,
"--no-tty"
,
"--batch"
},
batch
);
// TODO check status / error messages - probably not here, it's just started
// here, see finished for details
// https://github.com/IJHack/QtPass/issues/202#issuecomment-251081688
}
/**
* @brief Pass::listKeys list users
* @param keystrings
* @param secret list private keys
* @return QList<UserInfo> users
*/
QList
<
UserInfo
>
Pass
::
listKeys
(
QStringList
keystrings
,
bool
secret
)
{
QList
<
UserInfo
>
users
;
QStringList
args
=
{
"--no-tty"
,
"--with-colons"
};
args
.
append
(
secret
?
"--list-secret-keys"
:
"--list-keys"
);
foreach
(
QString
keystring
,
keystrings
)
{
if
(
!
keystring
.
isEmpty
())
{
args
.
append
(
keystring
);
}
}
QString
p_out
;
if
(
exec
.
executeBlocking
(
QtPassSettings
::
getGpgExecutable
(),
args
,
&
p_out
)
!=
0
)
return
users
;
QStringList
keys
=
p_out
.
split
(
QRegExp
(
"[
\r\n
]"
),
QString
::
SkipEmptyParts
);
UserInfo
current_user
;
foreach
(
QString
key
,
keys
)
{
QStringList
props
=
key
.
split
(
':'
);
if
(
props
.
size
()
<
10
)
continue
;
if
(
props
[
0
]
==
(
secret
?
"sec"
:
"pub"
))
{
if
(
!
current_user
.
key_id
.
isEmpty
())
users
.
append
(
current_user
);
current_user
=
UserInfo
();
current_user
.
key_id
=
props
[
4
];
current_user
.
name
=
props
[
9
].
toUtf8
();
current_user
.
validity
=
props
[
1
][
0
].
toLatin1
();
current_user
.
created
.
setTime_t
(
props
[
5
].
toUInt
());
current_user
.
expiry
.
setTime_t
(
props
[
6
].
toUInt
());
}
else
if
(
current_user
.
name
.
isEmpty
()
&&
props
[
0
]
==
"uid"
)
{
current_user
.
name
=
props
[
9
];
}
}
if
(
!
current_user
.
key_id
.
isEmpty
())
users
.
append
(
current_user
);
return
users
;
}
/**
* @brief Pass::listKeys list users
* @param keystring
* @param secret list private keys
* @return QList<UserInfo> users
*/
QList
<
UserInfo
>
Pass
::
listKeys
(
QString
keystring
,
bool
secret
)
{
return
listKeys
(
QStringList
(
keystring
),
secret
);
}
/**
* @brief Pass::processFinished reemits specific signal based on what process
* has finished
* @param id id of Pass process that was scheduled and finished
* @param exitCode return code of a process
* @param out output generated by process(if capturing was requested, empty
* otherwise)
* @param err error output generated by process(if capturing was requested,
* or error occured)
*/
void
Pass
::
finished
(
int
id
,
int
exitCode
,
const
QString
&
out
,
const
QString
&
err
)
{
PROCESS
pid
=
static_cast
<
PROCESS
>
(
id
);
if
(
exitCode
!=
0
)
{
emit
processErrorExit
(
exitCode
,
err
);
return
;
}
switch
(
pid
)
{
case
GIT_INIT
:
emit
finishedGitInit
(
out
,
err
);
break
;
case
GIT_PULL
:
emit
finishedGitPull
(
out
,
err
);
break
;
case
GIT_PUSH
:
emit
finishedGitPush
(
out
,
err
);
break
;
case
PASS_SHOW
:
emit
finishedShow
(
out
);
break
;
case
PASS_OTP_GENERATE
:
emit
finishedOtpGenerate
(
out
);
break
;
case
PASS_INSERT
:
emit
finishedInsert
(
out
,
err
);
break
;
case
PASS_REMOVE
:
emit
finishedRemove
(
out
,
err
);
break
;
case
PASS_INIT
:
emit
finishedInit
(
out
,
err
);
break
;
case
PASS_MOVE
:
emit
finishedMove
(
out
,
err
);
break
;
case
PASS_COPY
:
emit
finishedCopy
(
out
,
err
);
break
;
default
:
#ifdef QT_DEBUG
dbg
()
<<
"Unhandled process type"
<<
pid
;
#endif
break
;
}
}
/**
* @brief Pass::updateEnv update the execution environment (used when
* switching profiles)
*/
void
Pass
::
updateEnv
()
{
QStringList
store
=
env
.
filter
(
"PASSWORD_STORE_DIR"
);
// put PASSWORD_STORE_DIR in env
if
(
store
.
isEmpty
())
{
// dbg()<< "Added
// PASSWORD_STORE_DIR";
env
.
append
(
"PASSWORD_STORE_DIR="
+
QtPassSettings
::
getPassStore
());
}
else
{
// dbg()<< "Update
// PASSWORD_STORE_DIR with " + passStore;
env
.
replaceInStrings
(
store
.
first
(),
"PASSWORD_STORE_DIR="
+
QtPassSettings
::
getPassStore
());
}
exec
.
setEnvironment
(
env
);
}
/**
* @brief Pass::getRecipientList return list of gpg-id's to encrypt for
* @param for_file which file (folder) would you like recepients for
* @return recepients gpg-id contents
*/
QStringList
Pass
::
getRecipientList
(
QString
for_file
)
{
QDir
gpgIdPath
(
QFileInfo
(
for_file
.
startsWith
(
QtPassSettings
::
getPassStore
())
?
for_file
:
QtPassSettings
::
getPassStore
()
+
for_file
)
.
absoluteDir
());
bool
found
=
false
;
while
(
gpgIdPath
.
exists
()
&&
gpgIdPath
.
absolutePath
().
startsWith
(
QtPassSettings
::
getPassStore
()))
{
if
(
QFile
(
gpgIdPath
.
absoluteFilePath
(
".gpg-id"
)).
exists
())
{
found
=
true
;
break
;
}
if
(
!
gpgIdPath
.
cdUp
())
break
;
}
QFile
gpgId
(
found
?
gpgIdPath
.
absoluteFilePath
(
".gpg-id"
)
:
QtPassSettings
::
getPassStore
()
+
".gpg-id"
);
if
(
!
gpgId
.
open
(
QIODevice
::
ReadOnly
|
QIODevice
::
Text
))
return
QStringList
();
QStringList
recipients
;
while
(
!
gpgId
.
atEnd
())
{
QString
recipient
(
gpgId
.
readLine
());
recipient
=
recipient
.
trimmed
();
if
(
!
recipient
.
isEmpty
())
recipients
+=
recipient
;
}
return
recipients
;
}
/**
* @brief Pass::getRecipientString formated string for use with GPG
* @param for_file which file (folder) would you like recepients for
* @param separator formating separator eg: " -r "
* @param count
* @return recepient string
*/
QStringList
Pass
::
getRecipientString
(
QString
for_file
,
QString
separator
,
int
*
count
)
{
return
Pass
::
getRecipientList
(
for_file
);
}
/* Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
quint32
Pass
::
boundedRandom
(
quint32
bound
)
{
if
(
bound
<
2
)
{
return
0
;
}
quint32
randval
;
const
quint32
max_mod_bound
=
(
1
+
~
bound
)
%
bound
;
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
static
int
fd
=
-1
;
if
(
fd
==
-1
)
{
assert
((
fd
=
open
(
"/dev/urandom"
,
O_RDONLY
))
>=
0
);
}
#endif
do
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
assert
(
read
(
fd
,
&
randval
,
sizeof
(
randval
))
==
sizeof
(
randval
));
#else
randval
=
QRandomGenerator
::
system
()
->
generate
();
#endif
}
while
(
randval
<
max_mod_bound
);
return
randval
%
bound
;
}
QString
Pass
::
generateRandomPassword
(
const
QString
&
charset
,
unsigned
int
length
)
{
QString
out
;
for
(
unsigned
int
i
=
0
;
i
<
length
;
++
i
)
{
out
.
append
(
charset
.
at
(
static_cast
<
int
>
(
boundedRandom
(
static_cast
<
quint32
>
(
charset
.
length
())))));
}
return
out
;
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Feb 22, 6:49 PM (4 h, 44 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ab/f0/ae50cffa096cc6adc0f841dcc73f
Attached To
rGPGPASS GnuPG Password Manager
Event Timeline
Log In to Comment