Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7058388
PGP.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
PGP.php
View Options
<?php
namespace
App\Backends
;
use
App\User
;
use
Illuminate\Support\Facades\DB
;
use
Illuminate\Support\Facades\Storage
;
class
PGP
{
/** @var \Crypt_GPG GnuPG engine instance */
private
static
$gpg
;
/** @var array Crypt_GPG configuration */
private
static
$config
=
[];
/**
* Remove all files from the user homedir
*
* @param \App\User $user User object
* @param bool $del Delete also the homedir itself
*/
public
static
function
homedirCleanup
(
User
$user
,
bool
$del
=
false
):
void
{
$homedir
=
self
::
setHomedir
(
$user
);
// Remove all files from the filesystem (and optionally the dir itself)
if
(
$del
)
{
Storage
::
disk
(
'pgp'
)->
deleteDirectory
(
$homedir
);
}
else
{
Storage
::
disk
(
'pgp'
)->
delete
(
Storage
::
disk
(
'pgp'
)->
files
(
$homedir
));
foreach
(
Storage
::
disk
(
'pgp'
)->
files
(
$homedir
)
as
$subdir
)
{
Storage
::
disk
(
'pgp'
)->
deleteDirectory
(
$subdir
);
}
}
// Remove all files from the Enigma database
// Note: This will cause existing files in the Roundcube filesystem
// to be removed, but only if the user used the Enigma functionality
Roundcube
::
enigmaCleanup
(
$user
->
email
);
}
/**
* Generate a keypair.
* This will also initialize the user GPG homedir content.
*
* @param \App\User $user User object
* @param string $email Email address to use for the key
*
* @throws \Exception
*/
public
static
function
keypairCreate
(
User
$user
,
string
$email
):
void
{
self
::
initGPG
(
$user
,
true
);
if
(
$user
->
email
===
$email
)
{
// Make sure the homedir is empty for a new user
self
::
homedirCleanup
(
$user
);
}
$keygen
=
new
\Crypt_GPG_KeyGenerator
(
self
::
$config
);
$key
=
$keygen
// ->setPassphrase()
// ->setExpirationDate(0)
->
setKeyParams
(
\Crypt_GPG_SubKey
::
ALGORITHM_RSA
,
\config
(
'pgp.length'
))
->
setSubKeyParams
(
\Crypt_GPG_SubKey
::
ALGORITHM_RSA
,
\config
(
'pgp.length'
))
->
generateKey
(
null
,
$email
);
// Store the keypair in Roundcube Enigma storage
self
::
dbSave
(
true
);
// Get the ASCII armored data of the public key
$armor
=
self
::
$gpg
->
exportPublicKey
((
string
)
$key
,
true
);
// Register the public key in DNS
self
::
keyRegister
(
$email
,
$armor
);
// FIXME: Should we remove the files from the worker filesystem?
// They are still in database and Roundcube hosts' filesystem
}
/**
* Deleta a keypair from DNS and Enigma keyring.
*
* @param \App\User $user User object
* @param string $email Email address of the key
*
* @throws \Exception
*/
public
static
function
keyDelete
(
User
$user
,
string
$email
):
void
{
// Start with the DNS, it's more important
self
::
keyUnregister
(
$email
);
// Remove the whole Enigma keyring (if it's a delete user account)
if
(
$user
->
email
===
$email
)
{
self
::
homedirCleanup
(
$user
);
}
else
{
// TODO: remove only the alias key from Enigma keyring
}
}
/**
* List (public and private) keys from a user keyring.
*
* @param \App\User $user User object
*
* @returns \Crypt_GPG_Key[] List of keys
* @throws \Exception
*/
public
static
function
listKeys
(
User
$user
):
array
{
self
::
initGPG
(
$user
);
return
self
::
$gpg
->
getKeys
(
''
);
}
/**
* Debug logging callback
*/
public
static
function
logDebug
(
$msg
):
void
{
\Log
::
debug
(
"[GPG] $msg"
);
}
/**
* Register the key in the WOAT DNS system
*
* @param string $email Email address
* @param string $key The ASCII-armored key content
*/
private
static
function
keyRegister
(
string
$email
,
string
$key
):
void
{
list
(
$local
,
$domain
)
=
\App\Utils
::
normalizeAddress
(
$email
,
true
);
DB
::
beginTransaction
();
$domain
=
\App\PowerDNS\Domain
::
firstOrCreate
([
'name'
=>
'_woat.'
.
$domain
,
]);
\App\PowerDNS\Record
::
create
([
'domain_id'
=>
$domain
->
id
,
'name'
=>
sha1
(
$local
)
.
'.'
.
$domain
->
name
,
'type'
=>
'TXT'
,
'content'
=>
'v=woat1,public_key='
.
$key
]);
DB
::
commit
();
}
/**
* Remove the key from the WOAT DNS system
*
* @param string $email Email address
*/
private
static
function
keyUnregister
(
string
$email
):
void
{
list
(
$local
,
$domain
)
=
\App\Utils
::
normalizeAddress
(
$email
,
true
);
$domain
=
\App\PowerDNS\Domain
::
where
(
'name'
,
'_woat.'
.
$domain
)->
first
();
if
(
$domain
)
{
$fqdn
=
sha1
(
$local
)
.
'.'
.
$domain
->
name
;
// For now we support only one WOAT key record
$domain
->
records
()->
where
(
'name'
,
$fqdn
)->
delete
();
}
}
/**
* Prepare Crypt_GPG configuration
*/
private
static
function
initConfig
(
User
$user
,
$nosync
=
false
):
void
{
if
(!
empty
(
self
::
$config
)
&&
self
::
$config
[
'email'
]
==
$user
->
email
)
{
return
;
}
$debug
=
\config
(
'app.debug'
);
$binary
=
\config
(
'pgp.binary'
);
$agent
=
\config
(
'pgp.agent'
);
$gpgconf
=
\config
(
'pgp.gpgconf'
);
$dir
=
self
::
setHomedir
(
$user
);
$options
=
[
'email'
=>
$user
->
email
,
// this one is not a Crypt_GPG option
'dir'
=>
$dir
,
// this one is not a Crypt_GPG option
'homedir'
=>
\config
(
'filesystems.disks.pgp.root'
)
.
'/'
.
$dir
,
'debug'
=>
$debug
?
'App
\B
ackends
\P
GP::logDebug'
:
null
,
];
if
(
$binary
)
{
$options
[
'binary'
]
=
$binary
;
}
if
(
$agent
)
{
$options
[
'agent'
]
=
$agent
;
}
if
(
$gpgconf
)
{
$options
[
'gpgconf'
]
=
$gpgconf
;
}
self
::
$config
=
$options
;
// Sync the homedir directory content with the Enigma storage
if
(!
$nosync
)
{
self
::
dbSync
();
}
}
/**
* Initialize Crypt_GPG
*/
private
static
function
initGPG
(
User
$user
,
$nosync
=
false
):
void
{
self
::
initConfig
(
$user
,
$nosync
);
self
::
$gpg
=
new
\Crypt_GPG
(
self
::
$config
);
}
/**
* Prepare a homedir for the user
*/
private
static
function
setHomedir
(
User
$user
):
string
{
// Create a subfolder using two first digits of the user ID
$dir
=
sprintf
(
'%02d'
,
substr
((
string
)
$user
->
id
,
0
,
2
))
.
'/'
.
$user
->
email
;
Storage
::
disk
(
'pgp'
)->
makeDirectory
(
$dir
);
return
$dir
;
}
/**
* Synchronize keys database of a user
*/
private
static
function
dbSync
():
void
{
Roundcube
::
enigmaSync
(
self
::
$config
[
'email'
],
self
::
$config
[
'dir'
]);
}
/**
* Save the keys database
*/
private
static
function
dbSave
(
$is_empty
=
false
):
void
{
Roundcube
::
enigmaSave
(
self
::
$config
[
'email'
],
self
::
$config
[
'dir'
],
$is_empty
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, Jun 12, 4:48 AM (4 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
909738
Default Alt Text
PGP.php (7 KB)
Attached To
Mode
R2 kolab
Attached
Detach File
Event Timeline
Log In to Comment