CDS
view release on metacpan or search on metacpan
sub setPermissions {
my $o = shift;
my $cmd = shift;
$cmd->collect($o);
my $folderStore = $o->existingFolderStoreOrShowError // return;
$o->showStore($folderStore);
$folderStore->setPermissions($o->{permissions});
$o->{ui}->line('Changing permissions â¦');
my $logger = CDS::Commands::FolderStore::SetLogger->new($o, $folderStore->folder);
$folderStore->checkPermissions($logger) || $o->traversalFailed($folderStore);
$logger->summary;
$o->{ui}->space;
}
sub checkPermissions {
my $o = shift;
my $cmd = shift;
$cmd->collect($o);
my $folderStore = $o->existingFolderStoreOrShowError // return;
$o->showStore($folderStore);
$o->{ui}->line('Checking permissions â¦');
my $logger = CDS::Commands::FolderStore::CheckLogger->new($o, $folderStore->folder);
$folderStore->checkPermissions($logger) || $o->traversalFailed($folderStore);
$logger->summary;
$o->{ui}->space;
}
sub fixPermissions {
my $o = shift;
my $cmd = shift;
$cmd->collect($o);
my $folderStore = $o->existingFolderStoreOrShowError // return;
$o->showStore($folderStore);
$o->{ui}->line('Fixing permissions â¦');
my $logger = CDS::Commands::FolderStore::FixLogger->new($o, $folderStore->folder);
$folderStore->checkPermissions($logger) || $o->traversalFailed($folderStore);
$logger->summary;
$o->{ui}->space;
}
sub traversalFailed {
my $o = shift;
my $folderStore = shift;
$o->{ui}->space;
$o->{ui}->p('Traversal failed because a file or folder could not be accessed. You may have to fix the permissions manually, or run this command with other privileges.');
$o->{ui}->p('If you have root privileges, you can take over this store using:');
my $userName = getpwuid($<);
my $groupName = getgrgid($();
$o->{ui}->line($o->{ui}->gold(' sudo chown -R ', $userName, ':', $groupName, ' ', $folderStore->folder));
$o->{ui}->p('and then set the desired permission scheme:');
$o->{ui}->line($o->{ui}->gold(' cds set permissions of ', $folderStore->folder, ' to â¦'));
$o->{ui}->space;
exit(1);
}
sub addAccount {
my $o = shift;
my $cmd = shift;
$cmd->collect($o);
# Prepare
my $folderStore = $o->existingFolderStoreOrShowError // return;
my $publicKey = $o->publicKey // return;
# Upload the public key onto the store
my $error = $folderStore->put($publicKey->hash, $publicKey->object);
return $o->{ui}->error('Unable to upload the public key: ', $error) if $error;
# Create the account folder
my $folder = $folderStore->folder.'/accounts/'.$publicKey->hash->hex;
my $permissions = $folderStore->permissions;
$permissions->mkdir($folder, $permissions->accountFolderMode);
return $o->{ui}->error('Unable to create folder "', $folder, '".') if ! -d $folder;
$o->{ui}->pGreen('Account ', $publicKey->hash->hex, ' added.');
return 1;
}
sub publicKey {
my $o = shift;
return $o->{keyPairToken}->keyPair->publicKey if $o->{keyPairToken};
if ($o->{file}) {
my $bytes = CDS->readBytesFromFile($o->{file}) // return $o->{ui}->error('Cannot read "', $o->{file}, '".');
my $object = CDS::Object->fromBytes($bytes) // return $o->{ui}->error('"', $o->{file}, '" is not a public key.');
return CDS::PublicKey->fromObject($object) // return $o->{ui}->error('"', $o->{file}, '" is not a public key.');
}
return $o->{actor}->uiGetPublicKey($o->{accountToken}->actorHash, $o->{accountToken}->cliStore, $o->{actor}->preferredKeyPairToken);
}
sub removeAccount {
my $o = shift;
my $cmd = shift;
$cmd->collect($o);
# Prepare the folder
my $folderStore = $o->existingFolderStoreOrShowError // return;
my $folder = $folderStore->folder.'/accounts/'.$o->{hash}->hex;
my $deletedFolder = $folderStore->folder.'/accounts/deleted-'.$o->{hash}->hex;
# Rename, so that it is not visible any more
$o->recursivelyDelete($deletedFolder) if -e $deletedFolder;
return $o->{ui}->line('The account ', $o->{hash}->hex, ' does not exist.') if ! -e $folder;
rename($folder, $deletedFolder) || return $o->{ui}->error('Unable to rename the folder "', $folder, '".');
sub finalizeWrong {
my $o = shift;
$o->{ui}->line(@_);
return 1;
}
sub summary {
my $o = shift;
$o->{ui}->p(($o->{correct} + $o->{wrong}).' files and folders traversed.');
$o->{ui}->p('The permissions of ', $o->{wrong}, ' files and folders have been fixed.') if $o->{wrong} > 0;
$o->{ui}->pGreen('All permissions are OK.');
}
package CDS::Commands::FolderStore::Logger;
sub new {
my $class = shift;
my $parent = shift;
my $baseFolder = shift;
return bless {
ui => $parent->{ui},
store => $parent->{store},
baseFolder => $baseFolder,
correct => 0,
wrong => 0,
}, $class;
}
sub correct {
my $o = shift;
$o->{correct} += 1;
}
sub wrong {
my $o = shift;
my $item = shift;
my $uid = shift;
my $gid = shift;
my $mode = shift;
my $expectedUid = shift;
my $expectedGid = shift;
my $expectedMode = shift;
my $len = length $o->{baseFolder};
$o->{wrong} += 1;
$item = 'â¦'.substr($item, $len) if length $item > $len && substr($item, 0, $len) eq $o->{baseFolder};
my @changes;
push @changes, 'user '.&username($uid).' -> '.&username($expectedUid) if defined $expectedUid && $uid != $expectedUid;
push @changes, 'group '.&groupname($gid).' -> '.&groupname($expectedGid) if defined $expectedGid && $gid != $expectedGid;
push @changes, 'mode '.sprintf('%04o -> %04o', $mode, $expectedMode) if $mode != $expectedMode;
return $o->finalizeWrong(join(', ', @changes), "\t", $item);
}
sub username {
my $uid = shift;
return getpwuid($uid) // $uid;
}
sub groupname {
my $gid = shift;
return getgrgid($gid) // $gid;
}
sub accessError {
my $o = shift;
my $item = shift;
$o->{ui}->error('Error accessing ', $item, '.');
return 0;
}
sub setError {
my $o = shift;
my $item = shift;
$o->{ui}->error('Error setting permissions of ', $item, '.');
return 0;
}
package CDS::Commands::FolderStore::SetLogger;
use parent -norequire, 'CDS::Commands::FolderStore::Logger';
sub finalizeWrong {
my $o = shift;
return 1;
}
sub summary {
my $o = shift;
$o->{ui}->p(($o->{correct} + $o->{wrong}).' files and folders traversed.');
$o->{ui}->p('The permissions of ', $o->{wrong}, ' files and folders have been adjusted.') if $o->{wrong} > 0;
$o->{ui}->pGreen('All permissions are OK.');
}
# BEGIN AUTOGENERATED
package CDS::Commands::Get;
sub register {
my $class = shift;
my $cds = shift;
my $help = shift;
my $node000 = CDS::Parser::Node->new(0);
my $node001 = CDS::Parser::Node->new(0);
my $node002 = CDS::Parser::Node->new(0);
my $node003 = CDS::Parser::Node->new(1, {constructor => \&new, function => \&help});
my $node004 = CDS::Parser::Node->new(0);
my $node005 = CDS::Parser::Node->new(0);
my $node006 = CDS::Parser::Node->new(0);
my $node007 = CDS::Parser::Node->new(0);
my $node008 = CDS::Parser::Node->new(0);
my $node009 = CDS::Parser::Node->new(0);
for my $boxLabel (sort { $a cmp $b } CDS->listFolder($accountFolder)) {
next if $boxLabel =~ /^\./;
my $boxFolder = $accountFolder.'/'.$boxLabel;
$permissions->checkPermissions($boxFolder, $permissions->boxFolderMode($boxLabel), $logger) || return;
# Check each file
my $filePermissions = $permissions->boxFileMode($boxLabel);
for my $file (sort { $a cmp $b } CDS->listFolder($boxFolder)) {
next if $file !~ /^[0-9a-f]{64}/;
$permissions->checkPermissions($boxFolder.'/'.$file, $filePermissions, $logger) || return;
}
}
}
# Check the objects folder
my $objectsFolder = $o->{folder}.'/objects';
my $fileMode = $permissions->objectFileMode;
my $folderMode = $permissions->objectFolderMode;
$permissions->checkPermissions($objectsFolder, $folderMode, $logger) || return;
# Check the 256 sub folders
for my $sub (sort { $a cmp $b } CDS->listFolder($objectsFolder)) {
next if $sub !~ /^[0-9a-f][0-9a-f]$/;
my $subFolder = $objectsFolder.'/'.$sub;
$permissions->checkPermissions($subFolder, $folderMode, $logger) || return;
for my $file (sort { $a cmp $b } CDS->listFolder($subFolder)) {
next if $file !~ /^[0-9a-f]{62}/;
$permissions->checkPermissions($subFolder.'/'.$file, $fileMode, $logger) || return;
}
}
return 1;
}
# Handles POSIX permissions (user, group, and mode).
package CDS::FolderStore::PosixPermissions;
# Returns the permissions set corresponding to the mode, uid, and gid of the base folder.
# If the permissions are ambiguous, the more restrictive set is chosen.
sub forFolder {
my $class = shift;
my $folder = shift;
my @s = stat $folder;
my $mode = $s[2] // 0;
return
($mode & 077) == 077 ? CDS::FolderStore::PosixPermissions::World->new :
($mode & 070) == 070 ? CDS::FolderStore::PosixPermissions::Group->new($s[5]) :
CDS::FolderStore::PosixPermissions::User->new($s[4]);
}
sub uid { shift->{uid} }
sub gid { shift->{gid} }
sub user {
my $o = shift;
my $uid = $o->{uid} // return;
return getpwuid($uid) // $uid;
}
sub group {
my $o = shift;
my $gid = $o->{gid} // return;
return getgrgid($gid) // $gid;
}
sub writeTemporaryFile {
my $o = shift;
my $folder = shift;
my $mode = shift;
# Write the file
my $temporaryFile = $folder.'/.'.CDS->randomHex(16);
open(my $fh, '>:bytes', $temporaryFile) || return;
print $fh @_;
close $fh;
# Set the permissions
chmod $mode, $temporaryFile;
my $uid = $o->uid;
my $gid = $o->gid;
chown $uid // -1, $gid // -1, $temporaryFile if defined $uid && $uid != $< || defined $gid && $gid != $(;
return $temporaryFile;
}
sub mkdir {
my $o = shift;
my $folder = shift;
my $mode = shift;
return if -d $folder;
# Create the folder (note: mode is altered by umask)
my $success = mkdir $folder, $mode;
# Set the permissions
chmod $mode, $folder;
my $uid = $o->uid;
my $gid = $o->gid;
chown $uid // -1, $gid // -1, $folder if defined $uid && $uid != $< || defined $gid && $gid != $(;
return $success;
}
# Check the permissions of a file or folder, and fix them if desired.
# A logger object is called for the different cases (access error, correct permissions, wrong permissions, error fixing permissions).
sub checkPermissions {
my $o = shift;
my $item = shift;
my $expectedMode = shift;
my $logger = shift;
my $expectedUid = $o->uid;
my $expectedGid = $o->gid;
# Stat the item
my @s = stat $item;
return $logger->accessError($item) if ! scalar @s;
( run in 2.273 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )