diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d68ee6a..e7fb929 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,6 +58,8 @@ variables: services: - name: rroemhild/test-openldap alias: rroemhild-test-openldap + - name: swiftstack/picoswiftstack + alias: swiftstack-picoswiftstack .pg_template: &pg_definition <<: *tests_template needs: @@ -67,6 +69,8 @@ variables: alias: postgres - name: rroemhild/test-openldap alias: rroemhild-test-openldap + - name: swiftstack/picoswiftstack + alias: swiftstack-picoswiftstack .mysql_template: &mysql_definition <<: *tests_template needs: @@ -76,6 +80,8 @@ variables: alias: mariadb - name: rroemhild/test-openldap alias: rroemhild-test-openldap + - name: swiftstack/picoswiftstack + alias: swiftstack-picoswiftstack ### Publish tag changelog and create a toot ## diff --git a/CHANGELOG b/CHANGELOG index d046cfa..da507bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ Revision history for Lufi - Use Weblate instead of Zanata for translations (https://weblate.framasoft.org/projects/lufi/development/) - Add config API endpoint (#183) - Show latest tag and commit of the instance in about page and config API endpoint (#174) + - Add support for Swift object storage (EXPERIMENTAL) 0.04.6 2019-11-07 - Now can send large files (>2Gio) while using a DB other than SQLite (#165) diff --git a/Makefile b/Makefile index 58cfe91..5071551 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,14 @@ ldap: ldapdev: ldap dev +swift: + sudo docker run -d --rm -p 8080:8080 --hostname="picoswiftstack" --name="picoswiftstack" swiftstack/picoswiftstack; exit 0 + @echo "Sleeping 20 seconds to let picoswiftstack start" + @sleep 20 + sudo docker exec picoswiftstack get_auth + +swiftdev: swift dev + devlog: multitail log/development.log diff --git a/cpanfile b/cpanfile index b6909da..ca248b3 100644 --- a/cpanfile +++ b/cpanfile @@ -6,9 +6,9 @@ requires 'Mojolicious::Plugin::Mail'; requires 'Mojolicious::Plugin::GzipStatic'; requires 'Mojolicious::Plugin::StaticCache'; requires 'Mojolicious::Plugin::CSPHeader', '>= 0.06'; -requires 'Mojolicious::Plugin::FiatTux::Helpers', '== 0.10', url => 'https://framagit.org/fiat-tux/mojolicious/mojolicious-plugin-fiattux-helpers/-/archive/0.10/mojolicious-plugin-fiattux-helpers-0.10.tar.gz'; -requires 'Mojolicious::Plugin::FiatTux::GrantAccess', '== 0.06', url => 'https://framagit.org/fiat-tux/mojolicious/mojolicious-plugin-fiattux-grantaccess/-/archive/0.06/mojolicious-plugin-fiattux-grantaccess-0.06.tar.gz'; -requires 'Mojolicious::Plugin::FiatTux::Themes', '== 0.02', url => 'https://framagit.org/fiat-tux/mojolicious/mojolicious-plugin-fiattux-themes/-/archive/0.02/mojolicious-plugin-fiattux-themes-0.02.tar.gz'; +requires 'Mojolicious::Plugin::FiatTux::Helpers', '== 0.12', url => 'https://framagit.org/fiat-tux/mojolicious/fiat-tux/mojolicious-plugin-fiattux-helpers/-/archive/0.12/mojolicious-plugin-fiattux-helpers-0.12.tar.gz'; +requires 'Mojolicious::Plugin::FiatTux::GrantAccess', '== 0.07', url => 'https://framagit.org/fiat-tux/mojolicious/fiat-tux/mojolicious-plugin-fiattux-grantaccess/-/archive/0.07/mojolicious-plugin-fiattux-grantaccess-0.07.tar.gz'; +requires 'Mojolicious::Plugin::FiatTux::Themes', '== 0.02', url => 'https://framagit.org/fiat-tux/mojolicious/fiat-tux/mojolicious-plugin-fiattux-themes/-/archive/0.02/mojolicious-plugin-fiattux-themes-0.02.tar.gz'; requires 'Filesys::DiskUsage'; requires 'Switch'; requires 'Locale::Maketext'; @@ -55,3 +55,6 @@ feature 'mysql', 'MySQL support' => sub { requires 'Mojo::mysql'; requires 'Mojolicious::Plugin::PgURLHelper'; }; +feature 'swift-storage', 'Openstack Swift object storage support' => sub { + requires 'Net::OpenStack::Swift'; +}; diff --git a/cpanfile.snapshot b/cpanfile.snapshot index bfe4c0a..2a082c5 100644 --- a/cpanfile.snapshot +++ b/cpanfile.snapshot @@ -9,6 +9,23 @@ DISTRIBUTIONS Digest::SHA 2 ExtUtils::MakeMaker 0 MIME::Base64 0 + App-Rad-1.05 + pathname: G/GA/GARU/App-Rad-1.05.tar.gz + provides: + App::Rad 1.05 + App::Rad::Config undef + App::Rad::Exclude 0.01 + App::Rad::Help 0.03 + App::Rad::Include 0.01 + requirements: + Attribute::Handlers 0 + B::Deparse 0 + Carp 0 + ExtUtils::MakeMaker 0 + File::Temp 0 + FindBin 0 + Getopt::Long 2.36 + Test::More 0 Authen-SASL-2.16 pathname: G/GB/GBARR/Authen-SASL-2.16.tar.gz provides: @@ -39,6 +56,24 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Test::More 0 deprecate 0.03 + B-Hooks-EndOfScope-0.24 + pathname: E/ET/ETHER/B-Hooks-EndOfScope-0.24.tar.gz + provides: + B::Hooks::EndOfScope 0.24 + B::Hooks::EndOfScope::PP 0.24 + B::Hooks::EndOfScope::XS 0.24 + requirements: + ExtUtils::MakeMaker 0 + Hash::Util::FieldHash 0 + Module::Implementation 0.05 + Scalar::Util 0 + Sub::Exporter::Progressive 0.001006 + Text::ParseWords 0 + Tie::Hash 0 + Variable::Magic 0.48 + perl 5.006001 + strict 0 + warnings 0 Canary-Stability-2013 pathname: M/ML/MLEHMANN/Canary-Stability-2013.tar.gz provides: @@ -60,10 +95,16 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 - Class-Method-Modifiers-2.12 - pathname: E/ET/ETHER/Class-Method-Modifiers-2.12.tar.gz + Class-Accessor-Lite-0.08 + pathname: K/KA/KAZUHO/Class-Accessor-Lite-0.08.tar.gz provides: - Class::Method::Modifiers 2.12 + Class::Accessor::Lite 0.08 + requirements: + ExtUtils::MakeMaker 6.36 + Class-Method-Modifiers-2.13 + pathname: E/ET/ETHER/Class-Method-Modifiers-2.13.tar.gz + provides: + Class::Method::Modifiers 2.13 requirements: B 0 Carp 0 @@ -101,14 +142,22 @@ DISTRIBUTIONS ExtUtils::MakeMaker 6.30 Math::BigInt 1.997 Test::More 0.90 - Cpanel-JSON-XS-4.12 - pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.12.tar.gz + Cpanel-JSON-XS-4.19 + pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.19.tar.gz provides: - Cpanel::JSON::XS 4.12 + Cpanel::JSON::XS 4.19 Cpanel::JSON::XS::Type undef requirements: + Carp 0 + Config 0 + Encode 1.9801 + Exporter 0 ExtUtils::MakeMaker 0 Pod::Text 2.08 + XSLoader 0 + overload 0 + strict 0 + warnings 0 Crypt-PasswdMD5-1.40 pathname: R/RS/RSAVAGE/Crypt-PasswdMD5-1.40.tgz provides: @@ -135,25 +184,25 @@ DISTRIBUTIONS ExtUtils::MakeMaker 6.30 Test::Fatal 0 Test::More 0 - DBD-Pg-3.8.1 - pathname: T/TU/TURNSTEP/DBD-Pg-3.8.1.tar.gz + DBD-Pg-3.10.5 + pathname: T/TU/TURNSTEP/DBD-Pg-3.10.5.tar.gz provides: - Bundle::DBD::Pg v3.8.1 - DBD::Pg v3.8.1 + Bundle::DBD::Pg v3.10.5 + DBD::Pg v3.10.5 requirements: DBI 1.614 ExtUtils::MakeMaker 6.11 Test::More 0.88 Time::HiRes 0 version 0 - DBD-SQLite-1.62 - pathname: I/IS/ISHIGAKI/DBD-SQLite-1.62.tar.gz + DBD-SQLite-1.64 + pathname: I/IS/ISHIGAKI/DBD-SQLite-1.64.tar.gz provides: - DBD::SQLite 1.62 + DBD::SQLite 1.64 DBD::SQLite::Constants undef DBD::SQLite::GetInfo undef - DBD::SQLite::VirtualTable 1.62 - DBD::SQLite::VirtualTable::Cursor 1.62 + DBD::SQLite::VirtualTable 1.64 + DBD::SQLite::VirtualTable::Cursor 1.64 DBD::SQLite::VirtualTable::FileContent undef DBD::SQLite::VirtualTable::FileContent::Cursor undef DBD::SQLite::VirtualTable::PerlData undef @@ -162,8 +211,7 @@ DISTRIBUTIONS DBI 1.57 ExtUtils::MakeMaker 0 File::Spec 0.82 - Test::Builder 0.86 - Test::More 0.47 + Test::More 0.88 Tie::Hash 0 perl 5.006 DBD-mysql-4.050 @@ -181,8 +229,8 @@ DISTRIBUTIONS Devel::CheckLib 1.09 ExtUtils::MakeMaker 0 perl 5.008001 - DBI-1.642 - pathname: T/TI/TIMB/DBI-1.642.tar.gz + DBI-1.643 + pathname: T/TI/TIMB/DBI-1.643.tar.gz provides: Bundle::DBI 12.008696 DBD::DBM 0.08 @@ -238,7 +286,7 @@ DISTRIBUTIONS DBD::Sponge::dr 12.010003 DBD::Sponge::st 12.010003 DBDI 12.015129 - DBI 1.642 + DBI 1.643 DBI::Const::GetInfo::ANSI 2.008697 DBI::Const::GetInfo::ODBC 2.011374 DBI::Const::GetInfoReturn 2.008697 @@ -278,11 +326,11 @@ DISTRIBUTIONS DBI::SQL::Nano::Table_ 1.015544 DBI::Util::CacheMemory 0.010315 DBI::Util::_accessor 0.009479 - DBI::common 1.642 + DBI::common 1.643 requirements: ExtUtils::MakeMaker 6.48 Test::Simple 0.90 - perl 5.008 + perl 5.008001 Data-Entropy-0.007 pathname: Z/ZE/ZEFRAM/Data-Entropy-0.007.tar.gz provides: @@ -356,10 +404,40 @@ DISTRIBUTIONS Data::Validate::Domain 0 Data::Validate::IP 0 ExtUtils::MakeMaker 0 - Devel-CheckLib-1.13 - pathname: M/MA/MATTN/Devel-CheckLib-1.13.tar.gz + Data-Validator-1.07 + pathname: G/GF/GFUJI/Data-Validator-1.07.tar.gz provides: - Devel::CheckLib 1.13 + Data::Validator 1.07 + Data::Validator::Role::AllowExtra undef + Data::Validator::Role::Croak undef + Data::Validator::Role::Method undef + Data::Validator::Role::NoRestricted undef + Data::Validator::Role::NoThrow undef + Data::Validator::Role::Sequenced undef + Data::Validator::Role::SmartSequenced undef + Data::Validator::Role::StrictSequenced undef + requirements: + ExtUtils::MakeMaker 6.59 + Module::Build 0.38 + Mouse 0.93 + perl 5.008001 + Devel-CheckCompiler-0.07 + pathname: S/SY/SYOHEX/Devel-CheckCompiler-0.07.tar.gz + provides: + Devel::AssertC99 undef + Devel::CheckCompiler 0.07 + requirements: + Exporter 0 + ExtUtils::CBuilder 0 + File::Temp 0 + Module::Build::Tiny 0.035 + Test::More 0.98 + parent 0 + perl 5.008001 + Devel-CheckLib-1.14 + pathname: M/MA/MATTN/Devel-CheckLib-1.14.tar.gz + provides: + Devel::CheckLib 1.14 requirements: Exporter 0 ExtUtils::MakeMaker 0 @@ -425,14 +503,13 @@ DISTRIBUTIONS HTML::Entities 3.69 Storable 0 Test::More 0 - Devel-GlobalDestruction-0.14 - pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz + Devel-PPPort-3.58 + pathname: A/AT/ATOOMIC/Devel-PPPort-3.58.tar.gz provides: - Devel::GlobalDestruction 0.14 + Devel::PPPort 3.58 requirements: ExtUtils::MakeMaker 0 - Sub::Exporter::Progressive 0.001011 - perl 5.006 + FindBin 0 Digest-HMAC-1.03 pathname: G/GA/GAAS/Digest-HMAC-1.03.tar.gz provides: @@ -444,10 +521,22 @@ DISTRIBUTIONS Digest::SHA 1 ExtUtils::MakeMaker 0 perl 5.004 - EV-4.27 - pathname: M/ML/MLEHMANN/EV-4.27.tar.gz + Dist-CheckConflicts-0.11 + pathname: D/DO/DOY/Dist-CheckConflicts-0.11.tar.gz provides: - EV 4.27 + Dist::CheckConflicts 0.11 + requirements: + Carp 0 + Exporter 0 + ExtUtils::MakeMaker 6.30 + Module::Runtime 0.009 + base 0 + strict 0 + warnings 0 + EV-4.33 + pathname: M/ML/MLEHMANN/EV-4.33.tar.gz + provides: + EV 4.33 EV::MakeMaker undef requirements: Canary::Stability 0 @@ -474,6 +563,43 @@ DISTRIBUTIONS Scalar::Util 0 Test::More 0 perl 5.006 + Encode-3.05 + pathname: D/DA/DANKOGAI/Encode-3.05.tar.gz + provides: + Encode 3.05 + Encode::Alias 2.24 + Encode::Byte 2.04 + Encode::CJKConstants 2.02 + Encode::CN 2.03 + Encode::CN::HZ 2.10 + Encode::Config 2.05 + Encode::EBCDIC 2.02 + Encode::Encoder 2.03 + Encode::Encoding 2.08 + Encode::GSM0338 2.07 + Encode::Guess 2.08 + Encode::Internal 3.05 + Encode::JP 2.04 + Encode::JP::H2Z 2.02 + Encode::JP::JIS7 2.08 + Encode::KR 2.03 + Encode::KR::2022_KR 2.04 + Encode::MIME::Header 2.28 + Encode::MIME::Header::ISO_2022_JP 1.09 + Encode::MIME::Name 1.03 + Encode::Symbol 2.02 + Encode::TW 2.03 + Encode::UTF_EBCDIC 3.05 + Encode::Unicode 2.18 + Encode::Unicode::UTF7 2.10 + Encode::XS 3.05 + Encode::utf8 3.05 + encoding 2.22 + requirements: + Exporter 5.57 + ExtUtils::MakeMaker 0 + Storable 0 + parent 0.221 Encode-Locale-1.05 pathname: G/GA/GAAS/Encode-Locale-1.05.tar.gz provides: @@ -569,6 +695,27 @@ DISTRIBUTIONS Test::More 0 Test::Warn 0 perl 5.006 + Furl-3.13 + pathname: T/TO/TOKUHIROM/Furl-3.13.tar.gz + provides: + Furl 3.13 + Furl::ConnectionCache undef + Furl::HTTP 3.13 + Furl::Headers undef + Furl::Request undef + Furl::Response undef + Furl::ZlibStream undef + requirements: + Class::Accessor::Lite 0 + Encode 0 + HTTP::Parser::XS 0.11 + MIME::Base64 0 + Module::Build::Tiny 0.035 + Mozilla::CA 0 + Scalar::Util 0 + Socket 0 + Time::HiRes 0 + perl 5.008001 HTML-Parser-3.72 pathname: G/GA/GAAS/HTML-Parser-3.72.tar.gz provides: @@ -590,27 +737,25 @@ DISTRIBUTIONS HTML::Tagset 3.20 requirements: ExtUtils::MakeMaker 0 - HTTP-Cookies-6.04 - pathname: O/OA/OALDERS/HTTP-Cookies-6.04.tar.gz + HTTP-Cookies-6.08 + pathname: O/OA/OALDERS/HTTP-Cookies-6.08.tar.gz provides: - HTTP::Cookies 6.04 - HTTP::Cookies::Microsoft 6.04 - HTTP::Cookies::Netscape 6.04 + HTTP::Cookies 6.08 + HTTP::Cookies::Microsoft 6.08 + HTTP::Cookies::Netscape 6.08 requirements: Carp 0 ExtUtils::MakeMaker 0 HTTP::Date 6 HTTP::Headers::Util 6 HTTP::Request 0 - Time::Local 0 locale 0 perl 5.008001 strict 0 - vars 0 - HTTP-Daemon-6.05 - pathname: E/ET/ETHER/HTTP-Daemon-6.05.tar.gz + HTTP-Daemon-6.06 + pathname: O/OA/OALDERS/HTTP-Daemon-6.06.tar.gz provides: - HTTP::Daemon 6.05 + HTTP::Daemon 6.06 requirements: Carp 0 ExtUtils::MakeMaker 0 @@ -626,14 +771,17 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 - HTTP-Date-6.02 - pathname: G/GA/GAAS/HTTP-Date-6.02.tar.gz + HTTP-Date-6.05 + pathname: O/OA/OALDERS/HTTP-Date-6.05.tar.gz provides: - HTTP::Date 6.02 + HTTP::Date 6.05 requirements: + Exporter 0 ExtUtils::MakeMaker 0 - Time::Local 0 + Time::Local 1.28 + Time::Zone 0 perl 5.006002 + strict 0 HTTP-Lite-2.44 pathname: N/NE/NEILB/HTTP-Lite-2.44.tar.gz provides: @@ -645,23 +793,23 @@ DISTRIBUTIONS perl 5.005 strict 0 warnings 0 - HTTP-Message-6.18 - pathname: O/OA/OALDERS/HTTP-Message-6.18.tar.gz - provides: - HTTP::Config 6.18 - HTTP::Headers 6.18 - HTTP::Headers::Auth 6.18 - HTTP::Headers::ETag 6.18 - HTTP::Headers::Util 6.18 - HTTP::Message 6.18 - HTTP::Request 6.18 - HTTP::Request::Common 6.18 - HTTP::Response 6.18 - HTTP::Status 6.18 + HTTP-Message-6.22 + pathname: O/OA/OALDERS/HTTP-Message-6.22.tar.gz + provides: + HTTP::Config 6.22 + HTTP::Headers 6.22 + HTTP::Headers::Auth 6.22 + HTTP::Headers::ETag 6.22 + HTTP::Headers::Util 6.22 + HTTP::Message 6.22 + HTTP::Request 6.22 + HTTP::Request::Common 6.22 + HTTP::Response 6.22 + HTTP::Status 6.22 requirements: Carp 0 Compress::Raw::Zlib 0 - Encode 2.21 + Encode 3.01 Encode::Locale 1 Exporter 5.57 ExtUtils::MakeMaker 0 @@ -691,6 +839,14 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 HTTP::Headers 6 perl 5.008001 + HTTP-Parser-XS-0.17 + pathname: K/KA/KAZUHO/HTTP-Parser-XS-0.17.tar.gz + provides: + HTTP::Parser::XS 0.17 + HTTP::Parser::XS::PP undef + requirements: + ExtUtils::MakeMaker 6.36 + Test::More 0.96 Hash-Merge-0.300 pathname: R/RE/REHSACK/Hash-Merge-0.300.tar.gz provides: @@ -709,17 +865,17 @@ DISTRIBUTIONS Encode 2.10 Exporter 5.57 ExtUtils::MakeMaker 6.30 - IO-Socket-SSL-2.066 - pathname: S/SU/SULLR/IO-Socket-SSL-2.066.tar.gz + IO-Socket-SSL-2.068 + pathname: S/SU/SULLR/IO-Socket-SSL-2.068.tar.gz provides: - IO::Socket::SSL 2.066 + IO::Socket::SSL 2.068 IO::Socket::SSL::Intercept 2.056 - IO::Socket::SSL::OCSP_Cache 2.066 - IO::Socket::SSL::OCSP_Resolver 2.066 + IO::Socket::SSL::OCSP_Cache 2.068 + IO::Socket::SSL::OCSP_Resolver 2.068 IO::Socket::SSL::PublicSuffix undef - IO::Socket::SSL::SSL_Context 2.066 - IO::Socket::SSL::SSL_HANDLE 2.066 - IO::Socket::SSL::Session_Cache 2.066 + IO::Socket::SSL::SSL_Context 2.068 + IO::Socket::SSL::SSL_HANDLE 2.068 + IO::Socket::SSL::Session_Cache 2.068 IO::Socket::SSL::Utils 2.014 requirements: ExtUtils::MakeMaker 0 @@ -740,10 +896,10 @@ DISTRIBUTIONS Socket 1.94 Test::More 0.88 constant 1.03 - ISO-639_1-0.03 - pathname: L/LD/LDIDRY/ISO-639_1-0.03.tar.gz + ISO-639_1-0.04 + pathname: L/LD/LDIDRY/ISO-639_1-0.04.tar.gz provides: - ISO::639_1 0.03 + ISO::639_1 0.04 requirements: Module::Build::Tiny 0.035 perl 5.008001 @@ -795,6 +951,18 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 6.30 Locale::Maketext 1.17 + Log-Minimal-0.19 + pathname: K/KA/KAZEBURO/Log-Minimal-0.19.tar.gz + provides: + Log::Minimal 0.19 + requirements: + CPAN::Meta 0 + CPAN::Meta::Prereqs 0 + Data::Dumper 0 + ExtUtils::CBuilder 0 + Module::Build 0.38 + Scalar::Util 0 + Term::ANSIColor 0 MIME-Charset-1.012.2 pathname: N/NE/NEZUMI/MIME-Charset-1.012.2.tar.gz provides: @@ -816,14 +984,14 @@ DISTRIBUTIONS MIME::Base64 2.13 MIME::Charset v1.10.1 Test::More 0 - MIME-Lite-3.030 - pathname: R/RJ/RJBS/MIME-Lite-3.030.tar.gz - provides: - MIME::Lite 3.030 - MIME::Lite::IO_Handle 3.030 - MIME::Lite::IO_Scalar 3.030 - MIME::Lite::IO_ScalarArray 3.030 - MIME::Lite::SMTP 3.030 + MIME-Lite-3.031 + pathname: R/RJ/RJBS/MIME-Lite-3.031.tar.gz + provides: + MIME::Lite 3.031 + MIME::Lite::IO_Handle 3.031 + MIME::Lite::IO_Scalar 3.031 + MIME::Lite::IO_ScalarArray 3.031 + MIME::Lite::SMTP 3.031 MailTool undef requirements: Email::Date::Format 1.000 @@ -883,28 +1051,28 @@ DISTRIBUTIONS Net::Domain 1.05 Net::SMTP 1.03 Test::More 0 - Module-Build-0.4229 - pathname: L/LE/LEONT/Module-Build-0.4229.tar.gz - provides: - Module::Build 0.4229 - Module::Build::Base 0.4229 - Module::Build::Compat 0.4229 - Module::Build::Config 0.4229 - Module::Build::Cookbook 0.4229 - Module::Build::Dumper 0.4229 - Module::Build::Notes 0.4229 - Module::Build::PPMMaker 0.4229 - Module::Build::Platform::Default 0.4229 - Module::Build::Platform::MacOS 0.4229 - Module::Build::Platform::Unix 0.4229 - Module::Build::Platform::VMS 0.4229 - Module::Build::Platform::VOS 0.4229 - Module::Build::Platform::Windows 0.4229 - Module::Build::Platform::aix 0.4229 - Module::Build::Platform::cygwin 0.4229 - Module::Build::Platform::darwin 0.4229 - Module::Build::Platform::os2 0.4229 - Module::Build::PodParser 0.4229 + Module-Build-0.4231 + pathname: L/LE/LEONT/Module-Build-0.4231.tar.gz + provides: + Module::Build 0.4231 + Module::Build::Base 0.4231 + Module::Build::Compat 0.4231 + Module::Build::Config 0.4231 + Module::Build::Cookbook 0.4231 + Module::Build::Dumper 0.4231 + Module::Build::Notes 0.4231 + Module::Build::PPMMaker 0.4231 + Module::Build::Platform::Default 0.4231 + Module::Build::Platform::MacOS 0.4231 + Module::Build::Platform::Unix 0.4231 + Module::Build::Platform::VMS 0.4231 + Module::Build::Platform::VOS 0.4231 + Module::Build::Platform::Windows 0.4231 + Module::Build::Platform::aix 0.4231 + Module::Build::Platform::cygwin 0.4231 + Module::Build::Platform::darwin 0.4231 + Module::Build::Platform::os2 0.4231 + Module::Build::PodParser 0.4231 requirements: CPAN::Meta 2.142060 Cwd 0 @@ -954,6 +1122,32 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 + Module-Build-XSUtil-0.19 + pathname: H/HI/HIDEAKIO/Module-Build-XSUtil-0.19.tar.gz + provides: + Module::Build::XSUtil 0.19 + requirements: + Devel::CheckCompiler 0 + Devel::PPPort 0 + Exporter 0 + ExtUtils::CBuilder 0 + File::Basename 0 + File::Path 0 + Module::Build 0.4005 + XSLoader 0 + parent 0 + perl 5.008001 + Module-Implementation-0.09 + pathname: D/DR/DROLSKY/Module-Implementation-0.09.tar.gz + provides: + Module::Implementation 0.09 + requirements: + Carp 0 + ExtUtils::MakeMaker 0 + Module::Runtime 0.012 + Try::Tiny 0 + strict 0 + warnings 0 Module-Install-1.19 pathname: E/ET/ETHER/Module-Install-1.19.tar.gz provides: @@ -1033,10 +1227,10 @@ DISTRIBUTIONS Text::ParseWords 0 perl 5.008001 version 0 - Mojo-Pg-4.15 - pathname: S/SR/SRI/Mojo-Pg-4.15.tar.gz + Mojo-Pg-4.18 + pathname: S/SR/SRI/Mojo-Pg-4.18.tar.gz provides: - Mojo::Pg 4.15 + Mojo::Pg 4.18 Mojo::Pg::Database undef Mojo::Pg::Migrations undef Mojo::Pg::PubSub undef @@ -1044,23 +1238,23 @@ DISTRIBUTIONS Mojo::Pg::Transaction undef SQL::Abstract::Pg undef requirements: - DBD::Pg 3.005001 + DBD::Pg 3.007004 ExtUtils::MakeMaker 0 Mojolicious 8.03 SQL::Abstract 1.86 perl 5.010001 - Mojo-SQLite-3.002 - pathname: D/DB/DBOOK/Mojo-SQLite-3.002.tar.gz + Mojo-SQLite-3.003 + pathname: D/DB/DBOOK/Mojo-SQLite-3.003.tar.gz provides: - Mojo::SQLite 3.002 - Mojo::SQLite::Database 3.002 - Mojo::SQLite::Migrations 3.002 - Mojo::SQLite::PubSub 3.002 - Mojo::SQLite::Results 3.002 - Mojo::SQLite::Transaction 3.002 + Mojo::SQLite 3.003 + Mojo::SQLite::Database 3.003 + Mojo::SQLite::Migrations 3.003 + Mojo::SQLite::PubSub 3.003 + Mojo::SQLite::Results 3.003 + Mojo::SQLite::Transaction 3.003 requirements: Carp 0 - DBD::SQLite 1.54 + DBD::SQLite 1.64 DBI 1.627 File::Spec::Functions 0 File::Temp 0 @@ -1072,13 +1266,13 @@ DISTRIBUTIONS URI::db 0.15 URI::file 4.21 perl 5.010001 - Mojo-mysql-1.16 - pathname: T/TE/TEKKI/Mojo-mysql-1.16.tar.gz + Mojo-mysql-1.18 + pathname: T/TE/TEKKI/Mojo-mysql-1.18.tar.gz provides: Blog undef Blog::Controller::Posts undef Blog::Model::Posts undef - Mojo::mysql 1.16 + Mojo::mysql 1.18 Mojo::mysql::Database undef Mojo::mysql::Migrations undef Mojo::mysql::PubSub undef @@ -1091,8 +1285,8 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Mojolicious 8.03 SQL::Abstract 1.86 - Mojolicious-8.22 - pathname: S/SR/SRI/Mojolicious-8.22.tar.gz + Mojolicious-8.40 + pathname: S/SR/SRI/Mojolicious-8.40.tar.gz provides: Mojo undef Mojo::Asset undef @@ -1161,7 +1355,7 @@ DISTRIBUTIONS Mojo::UserAgent::Transactor undef Mojo::Util undef Mojo::WebSocket undef - Mojolicious 8.22 + Mojolicious 8.40 Mojolicious::Command undef Mojolicious::Command::Author::cpanify undef Mojolicious::Command::Author::generate undef @@ -1277,36 +1471,73 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 Mojolicious 7.33 - Moo-2.003004 - pathname: H/HA/HAARG/Moo-2.003004.tar.gz + Moo-2.004000 + pathname: H/HA/HAARG/Moo-2.004000.tar.gz provides: Method::Generate::Accessor undef Method::Generate::BuildAll undef Method::Generate::Constructor undef Method::Generate::DemolishAll undef - Moo 2.003004 + Moo 2.004000 Moo::HandleMoose undef Moo::HandleMoose::FakeConstructor undef Moo::HandleMoose::FakeMetaClass undef Moo::HandleMoose::_TypeMap undef Moo::Object undef - Moo::Role 2.003004 + Moo::Role 2.004000 Moo::_Utils undef Moo::_mro undef Moo::_strictures undef Moo::sification undef oo undef requirements: - Class::Method::Modifiers 1.1 - Devel::GlobalDestruction 0.11 + Class::Method::Modifiers 1.10 Exporter 5.57 ExtUtils::MakeMaker 0 Module::Runtime 0.014 - Role::Tiny 2.000004 - Scalar::Util 0 - Sub::Defer 2.003001 - Sub::Quote 2.003001 + Role::Tiny 2.001004 + Scalar::Util 1.00 + Sub::Defer 2.006006 + Sub::Quote 2.006006 perl 5.006 + Mouse-v2.5.10 + pathname: S/SK/SKAJI/Mouse-v2.5.10.tar.gz + provides: + Mouse v2.5.10 + Mouse::Exporter undef + Mouse::Meta::Attribute undef + Mouse::Meta::Class undef + Mouse::Meta::Method undef + Mouse::Meta::Method::Accessor undef + Mouse::Meta::Method::Constructor undef + Mouse::Meta::Method::Delegation undef + Mouse::Meta::Method::Destructor undef + Mouse::Meta::Module undef + Mouse::Meta::Role undef + Mouse::Meta::Role::Application undef + Mouse::Meta::Role::Application::RoleSummation undef + Mouse::Meta::Role::Composite undef + Mouse::Meta::Role::Method undef + Mouse::Meta::TypeConstraint undef + Mouse::Object undef + Mouse::PurePerl undef + Mouse::Role v2.5.10 + Mouse::Spec v2.5.10 + Mouse::TypeRegistry undef + Mouse::Util v2.5.10 + Mouse::Util::MetaRole undef + Mouse::Util::TypeConstraints undef + Squirrel undef + Squirrel::Role undef + Test::Mouse undef + ouse undef + requirements: + ExtUtils::CBuilder 0 + Module::Build 0.4005 + Module::Build::XSUtil 0.19 + Scalar::Util 1.14 + XSLoader 0.02 + perl 5.008005 Mozilla-CA-20180117 pathname: A/AB/ABH/Mozilla-CA-20180117.tar.gz provides: @@ -1315,10 +1546,10 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Test 0 perl 5.006 - Net-DNS-1.20 - pathname: N/NL/NLNETLABS/Net-DNS-1.20.tar.gz + Net-DNS-1.23 + pathname: N/NL/NLNETLABS/Net-DNS-1.23.tar.gz provides: - Net::DNS 1.20 + Net::DNS 1.23 Net::DNS::Domain 1726 Net::DNS::DomainName 1605 Net::DNS::DomainName1035 1605 @@ -1327,32 +1558,31 @@ DISTRIBUTIONS Net::DNS::Mailbox 1605 Net::DNS::Mailbox1035 1605 Net::DNS::Mailbox2535 1605 - Net::DNS::Nameserver 1692 - Net::DNS::Packet 1714 - Net::DNS::Parameters 1729 + Net::DNS::Nameserver 1761 + Net::DNS::Packet 1761 + Net::DNS::Parameters 1761 Net::DNS::Question 1726 - Net::DNS::RR 1726 + Net::DNS::RR 1762 Net::DNS::RR::A 1597 Net::DNS::RR::AAAA 1597 Net::DNS::RR::AFSDB 1597 - Net::DNS::RR::APL 1597 - Net::DNS::RR::APL::Item 1597 - Net::DNS::RR::CAA 1597 + Net::DNS::RR::APL 1741 + Net::DNS::RR::APL::Item 1741 + Net::DNS::RR::CAA 1771 Net::DNS::RR::CDNSKEY 1586 Net::DNS::RR::CDS 1586 - Net::DNS::RR::CERT 1729 + Net::DNS::RR::CERT 1773 Net::DNS::RR::CNAME 1597 - Net::DNS::RR::CSYNC 1597 + Net::DNS::RR::CSYNC 1741 Net::DNS::RR::DHCID 1597 - Net::DNS::RR::DLV 1528 Net::DNS::RR::DNAME 1597 - Net::DNS::RR::DNSKEY 1729 - Net::DNS::RR::DS 1729 + Net::DNS::RR::DNSKEY 1773 + Net::DNS::RR::DS 1774 Net::DNS::RR::EUI48 1597 Net::DNS::RR::EUI64 1597 Net::DNS::RR::GPOS 1528 Net::DNS::RR::HINFO 1597 - Net::DNS::RR::HIP 1597 + Net::DNS::RR::HIP 1749 Net::DNS::RR::IPSECKEY 1718 Net::DNS::RR::ISDN 1597 Net::DNS::RR::KEY 1528 @@ -1369,53 +1599,54 @@ DISTRIBUTIONS Net::DNS::RR::NAPTR 1597 Net::DNS::RR::NID 1597 Net::DNS::RR::NS 1597 - Net::DNS::RR::NSEC 1696 - Net::DNS::RR::NSEC3 1726 - Net::DNS::RR::NSEC3PARAM 1597 + Net::DNS::RR::NSEC 1749 + Net::DNS::RR::NSEC3 1749 + Net::DNS::RR::NSEC3PARAM 1741 Net::DNS::RR::NULL 1528 Net::DNS::RR::OPENPGPKEY 1597 - Net::DNS::RR::OPT 1717 - Net::DNS::RR::OPT::CHAIN 1717 - Net::DNS::RR::OPT::CLIENT_SUBNET 1717 - Net::DNS::RR::OPT::COOKIE 1717 - Net::DNS::RR::OPT::DAU 1717 - Net::DNS::RR::OPT::DHU 1717 - Net::DNS::RR::OPT::EXPIRE 1717 - Net::DNS::RR::OPT::KEY_TAG 1717 - Net::DNS::RR::OPT::N3U 1717 - Net::DNS::RR::OPT::PADDING 1717 - Net::DNS::RR::OPT::TCP_KEEPALIVE 1717 + Net::DNS::RR::OPT 1773 + Net::DNS::RR::OPT::CHAIN 1773 + Net::DNS::RR::OPT::CLIENT_SUBNET 1773 + Net::DNS::RR::OPT::COOKIE 1773 + Net::DNS::RR::OPT::DAU 1773 + Net::DNS::RR::OPT::DHU 1773 + Net::DNS::RR::OPT::EXPIRE 1773 + Net::DNS::RR::OPT::KEY_TAG 1773 + Net::DNS::RR::OPT::N3U 1773 + Net::DNS::RR::OPT::PADDING 1773 + Net::DNS::RR::OPT::TCP_KEEPALIVE 1773 Net::DNS::RR::PTR 1597 Net::DNS::RR::PX 1597 Net::DNS::RR::RP 1597 - Net::DNS::RR::RRSIG 1729 + Net::DNS::RR::RRSIG 1754 Net::DNS::RR::RT 1597 - Net::DNS::RR::SIG 1729 - Net::DNS::RR::SMIMEA 1597 + Net::DNS::RR::SIG 1754 + Net::DNS::RR::SMIMEA 1741 Net::DNS::RR::SOA 1597 Net::DNS::RR::SPF 1593 Net::DNS::RR::SRV 1597 - Net::DNS::RR::SSHFP 1597 + Net::DNS::RR::SSHFP 1741 Net::DNS::RR::TKEY 1528 - Net::DNS::RR::TLSA 1597 - Net::DNS::RR::TSIG 1726 + Net::DNS::RR::TLSA 1741 + Net::DNS::RR::TSIG 1774 Net::DNS::RR::TXT 1597 Net::DNS::RR::URI 1597 Net::DNS::RR::X25 1597 - Net::DNS::Resolver 1726 - Net::DNS::Resolver::Base 1727 + Net::DNS::RR::ZONEMD 1771 + Net::DNS::Resolver 1740 + Net::DNS::Resolver::Base 1771 Net::DNS::Resolver::MSWin32 1568 - Net::DNS::Resolver::Recurse 1737 + Net::DNS::Resolver::Recurse 1748 Net::DNS::Resolver::UNIX 1573 Net::DNS::Resolver::android 1568 Net::DNS::Resolver::cygwin 1719 Net::DNS::Resolver::os2 1568 Net::DNS::Resolver::os390 1719 - Net::DNS::Text 1726 - Net::DNS::Update 1726 - Net::DNS::ZoneFile 1709 - Net::DNS::ZoneFile::Generator 1709 - Net::DNS::ZoneFile::Text 1709 + Net::DNS::Text 1762 + Net::DNS::Update 1774 + Net::DNS::ZoneFile 1769 + Net::DNS::ZoneFile::Generator 1769 + Net::DNS::ZoneFile::Text 1769 requirements: Digest::HMAC 1.03 Digest::MD5 2.13 @@ -1458,6 +1689,31 @@ DISTRIBUTIONS strict 0 vars 0 warnings 0 + Net-OpenStack-Swift-0.15 + pathname: M/MA/MASAKYST/Net-OpenStack-Swift-0.15.tar.gz + provides: + Net::OpenStack::Swift 0.15 + Net::OpenStack::Swift::InnerKeystone::Base undef + Net::OpenStack::Swift::InnerKeystone::V1_0 undef + Net::OpenStack::Swift::InnerKeystone::V2_0 undef + Net::OpenStack::Swift::InnerKeystone::V3_0 undef + Net::OpenStack::Swift::Util undef + requirements: + App::Rad 0 + Data::Validator 0 + Furl 0 + IO::Socket::SSL 0 + JSON 0 + Log::Minimal 0 + Module::Build::Tiny 0.035 + Mouse 0 + Parallel::Fork::BossWorkerAsync 0 + Path::Tiny 0 + Sys::CPU 0 + Text::ASCIITable 0 + URI::Escape 0 + namespace::clean 0 + perl 5.010_001 Net-SSLeay-1.88 pathname: C/CH/CHRISN/Net-SSLeay-1.88.tar.gz provides: @@ -1489,6 +1745,44 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 POSIX 0 Test::More 0 + Package-Stash-0.38 + pathname: E/ET/ETHER/Package-Stash-0.38.tar.gz + provides: + Package::Stash 0.38 + Package::Stash::PP 0.38 + requirements: + B 0 + Carp 0 + Config 0 + Dist::CheckConflicts 0.02 + ExtUtils::MakeMaker 0 + File::Spec 0 + Getopt::Long 0 + Module::Implementation 0.06 + Package::Stash::XS 0.26 + Scalar::Util 0 + Symbol 0 + Text::ParseWords 0 + constant 0 + perl 5.008001 + strict 0 + warnings 0 + Package-Stash-XS-0.29 + pathname: E/ET/ETHER/Package-Stash-XS-0.29.tar.gz + provides: + Package::Stash::XS 0.29 + requirements: + ExtUtils::MakeMaker 0 + XSLoader 0 + perl 5.008001 + strict 0 + warnings 0 + Parallel-Fork-BossWorkerAsync-0.09 + pathname: J/JV/JVANNUCCI/Parallel-Fork-BossWorkerAsync-0.09.tar.gz + provides: + Parallel::Fork::BossWorkerAsync 0.09 + requirements: + ExtUtils::MakeMaker 0 Params-Classify-0.015 pathname: Z/ZE/ZEFRAM/Params-Classify-0.015.tar.gz provides: @@ -1502,11 +1796,37 @@ DISTRIBUTIONS perl 5.006001 strict 0 warnings 0 - Role-Tiny-2.000006 - pathname: H/HA/HAARG/Role-Tiny-2.000006.tar.gz + Path-Tiny-0.112 + pathname: D/DA/DAGOLDEN/Path-Tiny-0.112.tar.gz + provides: + Path::Tiny 0.112 + Path::Tiny::Error 0.112 + requirements: + Carp 0 + Cwd 0 + Digest 1.03 + Digest::SHA 5.45 + Encode 0 + Exporter 5.57 + ExtUtils::MakeMaker 6.17 + Fcntl 0 + File::Copy 0 + File::Glob 0 + File::Path 2.07 + File::Spec 0.86 + File::Temp 0.19 + File::stat 0 + constant 0 + overload 0 + perl 5.008001 + strict 0 + warnings 0 + warnings::register 0 + Role-Tiny-2.001004 + pathname: H/HA/HAARG/Role-Tiny-2.001004.tar.gz provides: - Role::Tiny 2.000006 - Role::Tiny::With 2.000006 + Role::Tiny 2.001004 + Role::Tiny::With 2.001004 requirements: Exporter 5.57 perl 5.006 @@ -1533,11 +1853,11 @@ DISTRIBUTIONS Sub::Exporter::Progressive 0.001013 requirements: ExtUtils::MakeMaker 0 - Sub-Quote-2.006003 - pathname: H/HA/HAARG/Sub-Quote-2.006003.tar.gz + Sub-Quote-2.006006 + pathname: H/HA/HAARG/Sub-Quote-2.006006.tar.gz provides: - Sub::Defer 2.006003 - Sub::Quote 2.006003 + Sub::Defer 2.006006 + Sub::Quote 2.006006 requirements: ExtUtils::MakeMaker 0 Scalar::Util 0 @@ -1563,6 +1883,12 @@ DISTRIBUTIONS Text::Balanced 2 if 0 perl 5.005 + Sys-CPU-0.52 + pathname: M/MK/MKODERER/Sys-CPU-0.52.tar.gz + provides: + Sys::CPU 0.52 + requirements: + ExtUtils::MakeMaker 0 Term-ProgressBar-2.22 pathname: M/MA/MANWAR/Term-ProgressBar-2.22.tar.gz provides: @@ -1626,10 +1952,10 @@ DISTRIBUTIONS Test::Builder 0.13 Test::Builder::Tester 1.02 perl 5.006 - Test-Warnings-0.026 - pathname: E/ET/ETHER/Test-Warnings-0.026.tar.gz + Test-Warnings-0.030 + pathname: E/ET/ETHER/Test-Warnings-0.030.tar.gz provides: - Test::Warnings 0.026 + Test::Warnings 0.030 requirements: Carp 0 Exporter 0 @@ -1639,6 +1965,16 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 + Text-ASCIITable-0.22 + pathname: L/LU/LUNATIC/Text-ASCIITable-0.22.tar.gz + provides: + Text::ASCIITable 0.22 + Text::ASCIITable::Wrap 0.2 + requirements: + Carp 0 + Encode 0 + List::Util 0 + perl v5.6.0 Text-Soundex-3.05 pathname: R/RJ/RJBS/Text-Soundex-3.05.tar.gz provides: @@ -1646,8 +1982,19 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 if 0 - TimeDate-2.30 - pathname: G/GB/GBARR/TimeDate-2.30.tar.gz + Time-Local-1.30 + pathname: D/DR/DROLSKY/Time-Local-1.30.tar.gz + provides: + Time::Local 1.30 + requirements: + Carp 0 + Exporter 0 + ExtUtils::MakeMaker 0 + constant 0 + parent 0 + strict 0 + TimeDate-2.32 + pathname: A/AT/ATOOMIC/TimeDate-2.32.tar.gz provides: Date::Format 2.24 Date::Format::Generic 2.24 @@ -1672,6 +2019,7 @@ DISTRIBUTIONS Date::Language::Icelandic 1.01 Date::Language::Italian 1.01 Date::Language::Norwegian 1.01 + Date::Language::Occitan 1.04 Date::Language::Oromo 0.99 Date::Language::Romanian 1.01 Date::Language::Russian 1.01 @@ -1685,8 +2033,9 @@ DISTRIBUTIONS Date::Language::TigrinyaEritrean 1.00 Date::Language::TigrinyaEthiopian 1.00 Date::Language::Turkish 1.0 - Date::Parse 2.30 + Date::Parse 2.32 Time::Zone 2.24 + TimeDate 1.21 requirements: ExtUtils::MakeMaker 0 Try-Tiny-0.30 @@ -1834,6 +2183,25 @@ DISTRIBUTIONS URI 1.40 URI::Nested 0.10 perl 5.008001 + Variable-Magic-0.62 + pathname: V/VP/VPIT/Variable-Magic-0.62.tar.gz + provides: + Variable::Magic 0.62 + requirements: + Carp 0 + Config 0 + Exporter 0 + ExtUtils::MakeMaker 0 + IO::Handle 0 + IO::Select 0 + IPC::Open3 0 + POSIX 0 + Socket 0 + Test::More 0 + XSLoader 0 + base 0 + lib 0 + perl 5.008 WWW-RobotRules-6.02 pathname: G/GA/GAAS/WWW-RobotRules-6.02.tar.gz provides: @@ -1860,38 +2228,38 @@ DISTRIBUTIONS perl 5.008001 strict 0 warnings 0 - common-sense-3.74 - pathname: M/ML/MLEHMANN/common-sense-3.74.tar.gz - provides: - common::sense 3.74 - requirements: - ExtUtils::MakeMaker 0 - libwww-perl-6.39 - pathname: O/OA/OALDERS/libwww-perl-6.39.tar.gz - provides: - LWP 6.39 - LWP::Authen::Basic 6.39 - LWP::Authen::Digest 6.39 - LWP::Authen::Ntlm 6.39 - LWP::ConnCache 6.39 - LWP::Debug 6.39 - LWP::Debug::TraceHTTP 6.39 - LWP::DebugFile 6.39 - LWP::MemberMixin 6.39 - LWP::Protocol 6.39 - LWP::Protocol::cpan 6.39 - LWP::Protocol::data 6.39 - LWP::Protocol::file 6.39 - LWP::Protocol::ftp 6.39 - LWP::Protocol::gopher 6.39 - LWP::Protocol::http 6.39 - LWP::Protocol::loopback 6.39 - LWP::Protocol::mailto 6.39 - LWP::Protocol::nntp 6.39 - LWP::Protocol::nogo 6.39 - LWP::RobotUA 6.39 - LWP::Simple 6.39 - LWP::UserAgent 6.39 + common-sense-3.75 + pathname: M/ML/MLEHMANN/common-sense-3.75.tar.gz + provides: + common::sense 3.75 + requirements: + ExtUtils::MakeMaker 0 + libwww-perl-6.44 + pathname: O/OA/OALDERS/libwww-perl-6.44.tar.gz + provides: + LWP 6.44 + LWP::Authen::Basic 6.44 + LWP::Authen::Digest 6.44 + LWP::Authen::Ntlm 6.44 + LWP::ConnCache 6.44 + LWP::Debug 6.44 + LWP::Debug::TraceHTTP 6.44 + LWP::DebugFile 6.44 + LWP::MemberMixin 6.44 + LWP::Protocol 6.44 + LWP::Protocol::cpan 6.44 + LWP::Protocol::data 6.44 + LWP::Protocol::file 6.44 + LWP::Protocol::ftp 6.44 + LWP::Protocol::gopher 6.44 + LWP::Protocol::http 6.44 + LWP::Protocol::loopback 6.44 + LWP::Protocol::mailto 6.44 + LWP::Protocol::nntp 6.44 + LWP::Protocol::nogo 6.44 + LWP::RobotUA 6.44 + LWP::Simple 6.44 + LWP::UserAgent 6.44 libwww::perl undef requirements: CPAN::Meta::Requirements 2.120620 @@ -1928,6 +2296,15 @@ DISTRIBUTIONS perl 5.008001 strict 0 warnings 0 + namespace-clean-0.27 + pathname: R/RI/RIBASUSHI/namespace-clean-0.27.tar.gz + provides: + namespace::clean 0.27 + requirements: + B::Hooks::EndOfScope 0.12 + ExtUtils::MakeMaker 0 + Package::Stash 0.23 + perl 5.008001 perl-ldap-0.66 pathname: M/MA/MARSCHAP/perl-ldap-0.66.tar.gz provides: diff --git a/lib/Lufi.pm b/lib/Lufi.pm index b97fba5..4f961f3 100644 --- a/lib/Lufi.pm +++ b/lib/Lufi.pm @@ -66,6 +66,12 @@ sub startup { # Helpers $self->plugin('Lufi::Plugin::Helpers'); + # Now helpers has been loaded, time to check Swift container + if ($config->{swift}) { + $self->check_swift_container(); + $self->log->info('EXPERIMENTAL Using Swift object storage'); + } + # Recurrent task Mojo::IOLoop->recurring(2 => sub { my $loop = shift; @@ -74,8 +80,10 @@ sub startup { }); # Create directory if needed - mkdir($self->config('upload_dir'), 0700) unless (-d $self->config('upload_dir')); - die ('The upload directory ('.$self->config('upload_dir').') is not writable') unless (-w $self->config('upload_dir')); + if (!defined($config->{swift})) { + mkdir($self->config('upload_dir'), 0700) unless (-d $self->config('upload_dir')); + die ('The upload directory ('.$self->config('upload_dir').') is not writable') unless (-w $self->config('upload_dir')); + } # Configure sessions my $sessions = Mojolicious::Sessions->new; diff --git a/lib/Lufi/Command/copyFilesToSwift.pm b/lib/Lufi/Command/copyFilesToSwift.pm new file mode 100644 index 0000000..860538e --- /dev/null +++ b/lib/Lufi/Command/copyFilesToSwift.pm @@ -0,0 +1,72 @@ +package Lufi::Command::copyFilesToSwift; +use Mojo::Base 'Mojolicious::Command'; +use File::Spec; +use Term::ProgressBar; + +has description => 'Copy files from filesystem to Swift object storage'; +has usage => sub { shift->extract_usage }; + +sub run { + my $c = shift; + + if ($c->app->config('swift')) { + $c->app->check_swift_container(); + my @dirs = glob(File::Spec->catdir($c->app->config('upload_dir'), '*')); + + unless (scalar(@dirs)) { + say sprintf('The configured upload_dir (%s) seems to be empty. Is `upload_dir` configured in lufi.conf?', $c->app->config('upload_dir')); + exit 1; + } + say sprintf('%d folders to upload to Swift (can\'t say how many files, or the total size, sorry). This can take some time.', scalar(@dirs)); + print 'Do you want to continue? [Y/n] '; + my $confirm = ; + + if ($confirm =~ m/yes|y/i) { + my $progress = Term::ProgressBar->new({ count => scalar(@dirs), ETA => 'linear', name => 'Copying to Swift'}); + for my $dir (@dirs) { + my @files = glob(File::Spec->catfile($dir, '*')); + for my $file (@files) { + my ($volume, $directories, $filename) = File::Spec->splitpath($file); + my @file_dirs = File::Spec->splitdir($directories); + my $short = ($file_dirs[-1] ne '') ? $file_dirs[-1] : $file_dirs[-2]; + my $path = File::Spec->catfile($short, $filename); + + open my $fh, '<', $file or die sprintf('Unable to open file %s: %s', $file, $!); + + $c->app->swift->put_object( + container_name => $c->app->config('swift')->{container}, + object_name => $path, + content_length => -s $file, + content => $fh + ); + close $fh; + } + $progress->update(); + } + say sprintf('The copy to Swift object storage has ended. You can test Lufi, then delete `%s` directory', $c->app->config('upload_dir')); + } else { + say 'You want to stop. No problem.'; + } + } else { + say 'You didn\'t configure `swift` in your config file. Exiting.'; + exit 1; + } +} + +=encoding utf8 + +=head1 NAME + +Lufi::Command::copyFilesToSwift Copy files from filesystem to Swift object storage + +=head1 SYNOPSIS + + Usage: script/lufi copyFilesToSwift + + This command needs you to: + - set `upload_dir` in your config file (otherwise, it will use the default path, `files` to copy files from) + - configure `swift` with correct informations in your config file + +=cut + +1; diff --git a/lib/Lufi/Command/sqliteToOtherDB.pm b/lib/Lufi/Command/sqliteToOtherDB.pm index 4c39ff3..0811357 100644 --- a/lib/Lufi/Command/sqliteToOtherDB.pm +++ b/lib/Lufi/Command/sqliteToOtherDB.pm @@ -1,5 +1,6 @@ package Lufi::Command::sqliteToOtherDB; use Mojo::Base 'Mojolicious::Command'; +use Lufi::DB::BreakingChange; use Lufi::DB::File; use Lufi::DB::Slice; use Lufi::DB::Invitation; @@ -9,7 +10,7 @@ use Term::ProgressBar; use Lufi::DefaultConfig qw($default_config); has description => 'Migrate the records from a SQLite db to the currently configured database'; -has usage => sub { shift->extract_usage }; +has usage => sub { shift->extract_usage }; sub run { my $c = shift; @@ -36,8 +37,9 @@ sub run { my $files = $sqlite->db->select('files', undef)->hashes; my $slices = $sqlite->db->select('slices', undef)->hashes; my $invitations = $sqlite->db->select('invitations', undef)->hashes; + my $changes = $sqlite->db->select('breakingchanges', undef)->hashes; - my $progress = Term::ProgressBar->new({count => $files->size + $slices->size + $invitations->size}); + my $progress = Term::ProgressBar->new({count => $files->size + $slices->size + $invitations->size + $changes->size}); $files->each(sub { my ($file, $num) = @_; @@ -69,7 +71,6 @@ sub run { Lufi::DB::Slice->new(app => $c->app) ->short($slice->{short}) ->j($slice->{j}) - ->path($slice->{path}) ->write(); $progress->update(); @@ -92,13 +93,22 @@ sub run { ->write(); $progress->update(); }); + $changes->each(sub { + my ($change, $num) = @_; + + Lufi::DB::BreakingChange->new(app => $c->app) + ->change($change->{change}) + ->ack($change->{ack}) + ->write(); + $progress->update(); + }); } =encoding utf8 =head1 NAME -Lufi::Command::cron::sqliteToOtherDB Migrate the records from a SQLite db to the currently configured database +Lufi::Command::sqliteToOtherDB Migrate the records from a SQLite db to the currently configured database =head1 SYNOPSIS diff --git a/lib/Lufi/Command/theme.pm b/lib/Lufi/Command/theme.pm index 185e5d5..5d7ad57 100644 --- a/lib/Lufi/Command/theme.pm +++ b/lib/Lufi/Command/theme.pm @@ -2,7 +2,7 @@ package Lufi::Command::theme; use Mojo::Base 'Mojolicious::Commands'; use FindBin qw($Bin); -use File::Spec qw(catfile cat dir); +use File::Spec qw(catfile catdir); use File::Path qw(make_path); has description => 'Create new theme skeleton.'; diff --git a/lib/Lufi/Controller/Files.pm b/lib/Lufi/Controller/Files.pm index 71b8c34..af31c6b 100644 --- a/lib/Lufi/Controller/Files.pm +++ b/lib/Lufi/Controller/Files.pm @@ -100,7 +100,8 @@ sub upload { } } # Check that we have enough space (multiplying by 2 since it's encrypted, it takes more place that the original file) - if ($json->{part} == 0 && ($json->{size} * 2) >= dfportable($c->config('upload_dir'))->{bavail}) { + # Only check if using filesystem, not Swift storage + if (!defined($c->config('swift')) && $json->{part} == 0 && ($json->{size} * 2) >= dfportable($c->config('upload_dir'))->{bavail}) { $stop = 1; return $ws->send(decode('UTF-8', encode_json( { @@ -190,19 +191,12 @@ sub upload { # If we already have a part, it's a resend because the websocket has been broken # In this case, we don't need to rewrite the file unless ($f->slices->grep(sub { $_->j == $json->{part} })->size) { - # Create directory - my $dir = catdir($c->config('upload_dir'), $f->short); - mkdir($dir, 0700) unless (-d $dir); - # Create slice file - my $file = catfile($dir, $json->{part}.'.part'); my $s = Lufi::DB::Slice->new( app => $c->app, short => $f->short, - j => $json->{part}, - path => $file - ); - Mojo::File->new($file)->spurt($text); + j => $json->{part} + )->store($text); push @{$f->slices}, $s; $s->write; @@ -327,7 +321,7 @@ sub download { # Get the slice my $e = $f->slices->[$num]; - my $text = Mojo::File->new($e->path)->slurp; + my $text = $e->retrieve(); my ($json2) = split('XXMOJOXX', $text, 2); $json2 = decode 'UTF-8', $json2; diff --git a/lib/Lufi/DB/File.pm b/lib/Lufi/DB/File.pm index e0c562c..0635bd0 100644 --- a/lib/Lufi/DB/File.pm +++ b/lib/Lufi/DB/File.pm @@ -148,13 +148,37 @@ sub delete { $c->slices->each(sub { my ($e, $num) = @_; - unlink $e->path; + $e->delete_file(); }); - rmdir Mojo::File->new($c->app->config('upload_dir'), $c->short); - $c->deleted(1); + $c->delete_path + ->deleted(1) + ->write; - $c->write; + return $c; +} + +=head2 delete_path + +=over 1 + +=item B : C<$c-Edelete_path()> + +=item B : none + +=item B : delete the directory of the slices on filesystem or Swift object storage +=item B : the db accessor object + +=back + +=cut + +sub delete_path { + my $c = shift; + + if (!defined($c->app->config('swift'))) { + rmdir Mojo::File->new($c->app->config('upload_dir'), $c->short); + } return $c; } diff --git a/lib/Lufi/DB/Slice.pm b/lib/Lufi/DB/Slice.pm index 932ac5e..e877953 100644 --- a/lib/Lufi/DB/Slice.pm +++ b/lib/Lufi/DB/Slice.pm @@ -1,14 +1,17 @@ # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lufi::DB::Slice; use Mojo::Base -base; +use Encode 'encode'; +use File::Spec::Functions; use Mojo::Collection 'c'; has 'short'; has 'j'; -has 'path'; has 'record' => 0; has 'app'; +=encoding utf8 + =head1 NAME Lufi::DB::Slice - DB abstraction layer for Lufi file @@ -28,8 +31,6 @@ Have a look at Lufi::DB::Slice::SQLite's code: it's simple and may be more under =item B : integer -=item B : string - =item B : A mojolicious object =back @@ -96,15 +97,121 @@ sub write { my $c = shift; if ($c->record) { - $c->app->dbi->db->query('UPDATE slices SET short = ?, j = ?, path = ? WHERE short = ? AND j = ?', $c->short, $c->j, $c->path, $c->short, $c->j); + $c->app->dbi->db->query('UPDATE slices SET short = ?, j = ? WHERE short = ? AND j = ?', $c->short, $c->j, $c->short, $c->j); } else { - $c->app->dbi->db->query('INSERT INTO slices (short, j, path) VALUES (?, ?, ?)', $c->short, $c->j, $c->path); + $c->app->dbi->db->query('INSERT INTO slices (short, j) VALUES (?, ?)', $c->short, $c->j); $c->record(1); } return $c; } +=head2 store + +=over 1 + +=item B : C<$c-Estore($text)> + +=item B : a scalar value + +=item B : will store the content to the object's path, either on filesystem or on Swift object storage + +=item B : the db accessor object + +=back + +=cut + +sub store { + my $c = shift; + my $text = shift; + + if ($c->app->config('swift')) { + $c->app->swift->put_object( + container_name => $c->app->config('swift')->{container}, + object_name => $c->get_path(), + content_length => length(Encode::encode_utf8($text)), + content => Encode::encode_utf8($text) + ); + } else { + # Create directory + my $dir = catfile($c->app->config('upload_dir'), $c->short); + mkdir($dir, 0700) unless (-d $dir); + + # Write file + my $file = catfile($c->app->config('upload_dir'), $c->get_path()); + Mojo::File->new($file)->spurt($text); + } + + return $c; +} + +=head2 retrieve + +=over 1 + +=item B : C<$c-Eretrieve> + +=item B : none + +=item B : get file from storage, either filesystem or Swift object storage + +=item B : the data from the file + +=back + +=cut + +sub retrieve { + my $c = shift; + my $upload = shift; + + if ($c->app->config('swift')) { + my $file; + $c->app->swift->get_object( + container_name => $c->app->config('swift')->{container}, + object_name => $c->get_path(), + write_code => sub { + my ($status, $message, $headers, $chunk) = @_; + $file .= $chunk; + } + ); + return Encode::decode_utf8($file); + } else { + my $file = catfile($c->app->config('upload_dir'), $c->get_path()); + return Mojo::File->new($file)->slurp; + } +} +=head2 delete_file + +=over 1 + +=item B : C<$c-Edelete_file()> + +=item B : none + +=item B : delete the file on filesystem or Swift object storage + +=item B : the db accessor object + +=back + +=cut + +sub delete_file { + my $c = shift; + + if ($c->app->config('swift')) { + $c->app->swift->delete_object({ + container_name => $c->app->config('swift')->{container}, + object_name => $c->get_path() + }); + } else { + my $file = catfile($c->app->config('upload_dir'), $c->get_path()); + unlink $file or warn sprintf('Could not unlink %s: %s', $file, $!); + } + return $c; +} =head2 get_slices_of_file =over 1 @@ -147,7 +254,7 @@ sub get_slices_of_file { =item B : none -=item B : delete all file records from database unconditionnally +=item B : delete all slices records from database unconditionnally =item B : nothing @@ -161,6 +268,50 @@ sub delete_all { $c->app->dbi->db->delete('slices'); } +=head2 path + +=over 1 + +=item B : C<$c-Epath()> + +=item B : non + +=item B : format the path of the file, relative to the directory of the Swift object storage + +=item B : the path of the file + +=back + +=cut + +sub get_path { + my $c = shift; + + return catfile($c->short, sprintf('%d.part', $c->j)); +} + +=head2 count + +=over 1 + +=item B : C<$c-Ecount()> + +=item B : none + +=item B : get count of slices records from database + +=item B : integer + +=back + +=cut + +sub count { + my $c = shift; + + return $c->app->dbi->db->query('SELECT count(*) AS count FROM slices')->hashes->first->{count}; +} + =head2 _slurp =over 1 @@ -195,7 +346,6 @@ sub _slurp { if ($slice) { $c->short($slice->{short}); $c->j($slice->{j}); - $c->path($slice->{path}); $c->record(1); } diff --git a/lib/Lufi/DB/Slice/Mysql.pm b/lib/Lufi/DB/Slice/Mysql.pm index cb55ed0..390a53a 100644 --- a/lib/Lufi/DB/Slice/Mysql.pm +++ b/lib/Lufi/DB/Slice/Mysql.pm @@ -7,6 +7,8 @@ sub new { $c = $c->SUPER::new(@_); + $c = $c->_slurp if defined $c->record; + return $c; } diff --git a/lib/Lufi/DB/Slice/Pg.pm b/lib/Lufi/DB/Slice/Pg.pm index defdf27..9b03ca7 100644 --- a/lib/Lufi/DB/Slice/Pg.pm +++ b/lib/Lufi/DB/Slice/Pg.pm @@ -7,6 +7,8 @@ sub new { $c = $c->SUPER::new(@_); + $c = $c->_slurp if defined $c->record; + return $c; } diff --git a/lib/Mounter.pm b/lib/Mounter.pm index 5408e0b..19b6dd4 100644 --- a/lib/Mounter.pm +++ b/lib/Mounter.pm @@ -27,6 +27,9 @@ sub startup { # Compress static assets $self->plugin('GzipStatic'); + # Fiat Tux helpers + $self->plugin('FiatTux::Helpers'); + # Headers $self->plugin('Lufi::Plugin::Headers'); diff --git a/lufi.conf.template b/lufi.conf.template index c60cdf9..b7fd9fe 100644 --- a/lufi.conf.template +++ b/lufi.conf.template @@ -99,14 +99,30 @@ # Array of authorized domains for API calls. # If you want to authorize everyone to use the API: ['*'] # optional, no domains allowed by default - #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], # Define a path to the upload directory, where the uploaded files will be stored # You can define it relative to lufi directory or set an absolute path # Remember that it has to be in a directory writable by Lufi user - # DO NOT CHANGE THIS IF FILES HAVE BEEN ALREADY UPLOADED: THEY WILL NOT BE DOWNLOADABLE ANYMORE # optional, default is 'files' - #upload_dir => 'files', + #upload_dir => 'files', + + #!!!!!!!!!!!!!!! + # EXPERIMENTAL ! + #!!!!!!!!!!!!!!! + # You can store files on Swift object storage (https://en.wikipedia.org/wiki/OpenStack#Swift) instead of filesystem + # Please read https://metacpan.org/pod/Net::OpenStack::Swift#SYNOPSIS to know how to configure this setting + # IMPORTANT: add a `container` key in it, to let Lufi know which container to use. This is not a regular Net::OpenStack::Swift setting, but Lufi need it. + # EXPERIMENTAL: if the upload or download of files are stucked, reload Lufi and create a cron task to reload Lufi once a day + # You can copy Lufi files to Swift object storage by launching the command `carton exec script/lufi copyFilesToSwift` (can take a long time) + # optional, no default + #swift => { + # auth_url => 'https://auth-endpoint-url/v2.0', + # user => 'userid', + # password => 'password', + # tenant_name => 'project_id', + # container => 'lufi' + #}, # Allow to add a password on files, asked before allowing to download files # optional, default is 0 diff --git a/t/mysql.conf b/t/mysql.conf index 68f9bdb..51a2d80 100644 --- a/t/mysql.conf +++ b/t/mysql.conf @@ -32,6 +32,10 @@ # optional, default is ['fdjsofjoihrei'], PLEASE, CHANGE IT #secrets => ['fdjsofjoihrei'], + # Name of the instance, displayed next to the logo + # optional, default is Lufi + #instance_name => 'Lufi', + # Choose a theme. See the available themes in `themes` directory # Optional, default is 'default' #theme => 'default', @@ -97,10 +101,6 @@ # optional, no domains allowed by default #allowed_domains => ['http://1.example.com', 'http://2.example.com'], - # If set, the shortened URLs will use this domain - # optional - #fixed_domain => 'example.org', - # Define a path to the upload directory, where the uploaded files will be stored # You can define it relative to lufi directory or set an absolute path # Remember that it has to be in a directory writable by Lufi user @@ -108,6 +108,12 @@ # optional, default is 'files' #upload_dir => 'files', + # You can store files on Swift object storage (https://en.wikipedia.org/wiki/OpenStack#Swift) instead of filesystem + # Please read https://metacpan.org/pod/Net::OpenStack::Swift#SYNOPSIS to know how to configure this setting + # IMPORTANT: add a `container` key in it, to let Lufi know which container to use. This is not a regular Net::OpenStack::Swift setting, but Lufi need it. + # optional, no default + #swift => { auth_url => 'http://swiftstack-picoswiftstack:8080/auth/v1.0', user => 'test', password => 'test', container => 'lufi', auth_version => '1.0' }, + # Allow to add a password on files, asked before allowing to download files # optional, default is 0 allow_pwd_on_files => 1, @@ -228,11 +234,47 @@ # # Define the attributes like this: `lufi_attribute_name => 'LDAP_attribute_name'` # Note that you can’t use `username` as a Lufi attribute name: this name is reserved and will contain the login of the user + # optional, no default #ldap_map_attr => { # displayname => 'cn', # mail => 'mail' #}, + # When using LDAP authentication, LDAP users can invite people (by mail) to use Lufi to send them files without + # being authenticated. + # This is where you configure the behavior of the invitations. + # You may need to fetch some attributes from LDAP to use some invitations settings. See `ldap_map_attr` above. + # optional, no default + #invitations => { + # # The name of the key set in `ldap_map_attr` (above) that corresponds to the mail of the LDAP user + # # optional, default is `mail` + # mail_attr => 'mail', + # # The `From` header of invitation mail can be the mail of the LDAP user + # # Be sure to have a mail system that will correctly send the mail from your users! (DKIM, SPF…) + # # To enable this feature, set it to 1 + # # optional, disabled by default + # send_invitation_with_ldap_user_mail => 1, + # # The user is able to set an expiration delay for the invitation. + # # This expiration delay can’t be more than this setting (in days). + # # optional, default is 30 days + # max_invitation_expiration_delay => 30, + # # Once the guest has submitted his files, he has an additional period of time to submit forgotten files. + # # You can set that additional period of time in minutes here. + # # To disable that feature, set it to 0 or less + # # optional, default is 10 minutes + # max_additional_period => 10, + # # Lufi follows privacy-by-design, so, by default, no files URLs (with the decode secret) are stored in database. + # # However, the concern is different for this case. Storing files URLs makes users able to retrieve the guests’ sent files + # # from their `invitations` page. + # # Set to 1 to store guests’ files URLs in database + # # optional, default is 0 (disabled) + # save_files_url_in_db => 0, + # # Users can resend the invitation to their guest. This does not extend the invitation’s expiration delay unless you + # # set this option to 1. + # # optional, default is 0 (disabled) + # extend_invitation_expiration_on_resend => 0, + #}, + ######################### # Htpasswd authentication ######################### diff --git a/t/postgresql.conf b/t/postgresql.conf index 702da4a..0ac7cfe 100644 --- a/t/postgresql.conf +++ b/t/postgresql.conf @@ -32,6 +32,10 @@ # optional, default is ['fdjsofjoihrei'], PLEASE, CHANGE IT #secrets => ['fdjsofjoihrei'], + # Name of the instance, displayed next to the logo + # optional, default is Lufi + #instance_name => 'Lufi', + # Choose a theme. See the available themes in `themes` directory # Optional, default is 'default' #theme => 'default', @@ -97,10 +101,6 @@ # optional, no domains allowed by default #allowed_domains => ['http://1.example.com', 'http://2.example.com'], - # If set, the shortened URLs will use this domain - # optional - #fixed_domain => 'example.org', - # Define a path to the upload directory, where the uploaded files will be stored # You can define it relative to lufi directory or set an absolute path # Remember that it has to be in a directory writable by Lufi user @@ -108,6 +108,12 @@ # optional, default is 'files' #upload_dir => 'files', + # You can store files on Swift object storage (https://en.wikipedia.org/wiki/OpenStack#Swift) instead of filesystem + # Please read https://metacpan.org/pod/Net::OpenStack::Swift#SYNOPSIS to know how to configure this setting + # IMPORTANT: add a `container` key in it, to let Lufi know which container to use. This is not a regular Net::OpenStack::Swift setting, but Lufi need it. + # optional, no default + #swift => { auth_url => 'http://swiftstack-picoswiftstack:8080/auth/v1.0', user => 'test', password => 'test', container => 'lufi', auth_version => '1.0' }, + # Allow to add a password on files, asked before allowing to download files # optional, default is 0 allow_pwd_on_files => 1, @@ -172,6 +178,7 @@ #port => 5432, user => 'lufi', pwd => 'lufi_pwd' + # # https://mojolicious.org/perldoc/Mojo/Pg#max_connections # # optional, default is 1 # #max_connections => 1, }, @@ -212,11 +219,47 @@ # # Define the attributes like this: `lufi_attribute_name => 'LDAP_attribute_name'` # Note that you can’t use `username` as a Lufi attribute name: this name is reserved and will contain the login of the user + # optional, no default #ldap_map_attr => { # displayname => 'cn', # mail => 'mail' #}, + # When using LDAP authentication, LDAP users can invite people (by mail) to use Lufi to send them files without + # being authenticated. + # This is where you configure the behavior of the invitations. + # You may need to fetch some attributes from LDAP to use some invitations settings. See `ldap_map_attr` above. + # optional, no default + #invitations => { + # # The name of the key set in `ldap_map_attr` (above) that corresponds to the mail of the LDAP user + # # optional, default is `mail` + # mail_attr => 'mail', + # # The `From` header of invitation mail can be the mail of the LDAP user + # # Be sure to have a mail system that will correctly send the mail from your users! (DKIM, SPF…) + # # To enable this feature, set it to 1 + # # optional, disabled by default + # send_invitation_with_ldap_user_mail => 1, + # # The user is able to set an expiration delay for the invitation. + # # This expiration delay can’t be more than this setting (in days). + # # optional, default is 30 days + # max_invitation_expiration_delay => 30, + # # Once the guest has submitted his files, he has an additional period of time to submit forgotten files. + # # You can set that additional period of time in minutes here. + # # To disable that feature, set it to 0 or less + # # optional, default is 10 minutes + # max_additional_period => 10, + # # Lufi follows privacy-by-design, so, by default, no files URLs (with the decode secret) are stored in database. + # # However, the concern is different for this case. Storing files URLs makes users able to retrieve the guests’ sent files + # # from their `invitations` page. + # # Set to 1 to store guests’ files URLs in database + # # optional, default is 0 (disabled) + # save_files_url_in_db => 0, + # # Users can resend the invitation to their guest. This does not extend the invitation’s expiration delay unless you + # # set this option to 1. + # # optional, default is 0 (disabled) + # extend_invitation_expiration_on_resend => 0, + #}, + ######################### # Htpasswd authentication ######################### diff --git a/t/sqlite.conf b/t/sqlite.conf index fb1b55e..bebca16 100644 --- a/t/sqlite.conf +++ b/t/sqlite.conf @@ -32,6 +32,10 @@ # optional, default is ['fdjsofjoihrei'], PLEASE, CHANGE IT #secrets => ['fdjsofjoihrei'], + # Name of the instance, displayed next to the logo + # optional, default is Lufi + #instance_name => 'Lufi', + # Choose a theme. See the available themes in `themes` directory # Optional, default is 'default' #theme => 'default', @@ -97,10 +101,6 @@ # optional, no domains allowed by default #allowed_domains => ['http://1.example.com', 'http://2.example.com'], - # If set, the shortened URLs will use this domain - # optional - #fixed_domain => 'example.org', - # Define a path to the upload directory, where the uploaded files will be stored # You can define it relative to lufi directory or set an absolute path # Remember that it has to be in a directory writable by Lufi user @@ -108,6 +108,12 @@ # optional, default is 'files' #upload_dir => 'files', + # You can store files on Swift object storage (https://en.wikipedia.org/wiki/OpenStack#Swift) instead of filesystem + # Please read https://metacpan.org/pod/Net::OpenStack::Swift#SYNOPSIS to know how to configure this setting + # IMPORTANT: add a `container` key in it, to let Lufi know which container to use. This is not a regular Net::OpenStack::Swift setting, but Lufi need it. + # optional, no default + #swift => { auth_url => 'http://swiftstack-picoswiftstack:8080/auth/v1.0', user => 'test', password => 'test', container => 'lufi', auth_version => '1.0' }, + # Allow to add a password on files, asked before allowing to download files # optional, default is 0 allow_pwd_on_files => 1, @@ -217,11 +223,47 @@ # # Define the attributes like this: `lufi_attribute_name => 'LDAP_attribute_name'` # Note that you can’t use `username` as a Lufi attribute name: this name is reserved and will contain the login of the user + # optional, no default #ldap_map_attr => { # displayname => 'cn', # mail => 'mail' #}, + # When using LDAP authentication, LDAP users can invite people (by mail) to use Lufi to send them files without + # being authenticated. + # This is where you configure the behavior of the invitations. + # You may need to fetch some attributes from LDAP to use some invitations settings. See `ldap_map_attr` above. + # optional, no default + #invitations => { + # # The name of the key set in `ldap_map_attr` (above) that corresponds to the mail of the LDAP user + # # optional, default is `mail` + # mail_attr => 'mail', + # # The `From` header of invitation mail can be the mail of the LDAP user + # # Be sure to have a mail system that will correctly send the mail from your users! (DKIM, SPF…) + # # To enable this feature, set it to 1 + # # optional, disabled by default + # send_invitation_with_ldap_user_mail => 1, + # # The user is able to set an expiration delay for the invitation. + # # This expiration delay can’t be more than this setting (in days). + # # optional, default is 30 days + # max_invitation_expiration_delay => 30, + # # Once the guest has submitted his files, he has an additional period of time to submit forgotten files. + # # You can set that additional period of time in minutes here. + # # To disable that feature, set it to 0 or less + # # optional, default is 10 minutes + # max_additional_period => 10, + # # Lufi follows privacy-by-design, so, by default, no files URLs (with the decode secret) are stored in database. + # # However, the concern is different for this case. Storing files URLs makes users able to retrieve the guests’ sent files + # # from their `invitations` page. + # # Set to 1 to store guests’ files URLs in database + # # optional, default is 0 (disabled) + # save_files_url_in_db => 0, + # # Users can resend the invitation to their guest. This does not extend the invitation’s expiration delay unless you + # # set this option to 1. + # # optional, default is 0 (disabled) + # extend_invitation_expiration_on_resend => 0, + #}, + ######################### # Htpasswd authentication ######################### diff --git a/t/test.t b/t/test.t index 78fa19b..5d0da45 100644 --- a/t/test.t +++ b/t/test.t @@ -13,18 +13,19 @@ use FindBin qw($Bin); my ($m, $cfile, $config_orig, $config_file, $config_content); -my $msg = to_json { +my $msg = Encode::encode_utf8(to_json { "total" => 1, "part" => 0, "size" => 7, - "name" => "foobar.txt", + "name" => "foobaré.txt", "type" => "text/plain", "delay" => "0", "del_at_first_view" => 1, "id" => undef, "zipped" => 0, "i" => 0 -}; +}); +my $filename_test = Encode::encode_utf8('foobaré'); my $encrypted = '"{\\"iv\\":\\"2RGAviAeYybBqcLCmnqlgA==\\",\\"v\\":1,\\"iter\\":10000,\\"ks\\":128,\\"ts\\":64,\\"mode\\":\\"ccm\\",\\"adata\\":\\"\\",\\"cipher\\":\\"aes\\",\\"salt\\":\\"1dvKtbZ8hxA=\\",\\"ct\\":\\"w9wDZCwNSyH/yL7q1GW5fPSdi+w=\\"}"'; my $encrypted_rgx = $encrypted; $encrypted_rgx =~ s@\\@\\\\@g; @@ -77,6 +78,9 @@ BEGIN { Lufi::DB::Slice->new(app => $m)->delete_all; Lufi::DB::File->new(app => $m)->delete_all; +$config_file = Mojo::File->new($cfile->to_abs->to_string); +$config_orig = $config_file->slurp; + my $t = Test::Mojo->new('Lufi'); ## Wait for short generation @@ -103,6 +107,12 @@ test_infos_api(true); auth_test_suite('zoidberg', 'zoidberg'); restore_config(); +## Test Swift object storage +switch_to_swift(); +test_upload_file(); +test_download_file(); +restore_config(); + done_testing(); ###### @@ -145,7 +155,7 @@ sub test_upload_file { ->message_like(qr@"duration":\d+@) ->message_like(qr@"i":0@) ->message_like(qr@"j":0@) - ->message_like(qr@"name":"foobar\.txt"@) + ->message_like(qr@"name":"$filename_test\.txt"@) ->message_like(qr@"parts":1@) ->message_like(qr@"sent_delay":0@) ->message_like(qr@"short":"[^"]+"@) @@ -183,7 +193,7 @@ sub test_download_file { ->message_like(qr@"id":null@) ->message_like(qr@"del_at_first_view":1@) ->message_like(qr@"delay":"0"@) - ->message_like(qr@"name":"foobar\.txt"@) + ->message_like(qr@"name":"$filename_test\.txt"@) ->message_like(qr@"size":7@) ->message_like(qr@"type":"text\\/plain"@) ->message_like(qr@XXMOJOXX@) @@ -263,9 +273,7 @@ sub restore_config { } sub switch_to_htpasswd { - $config_file = Mojo::File->new($cfile->to_abs->to_string); - $config_content = $config_file->slurp; - $config_orig = $config_content; + $config_content = $config_orig; $config_content =~ s/#?htpasswd.*/htpasswd => 't\/lufi.passwd',/gm; $config_file->spurt($config_content); @@ -291,3 +299,17 @@ sub switch_to_ldap { ## Wait for short generation sleep 5; } + +sub switch_to_swift { + $config_content = $config_orig; + $config_content =~ s/^( +)#?swift => \{ auth_url/$1swift => { auth_url/gm; + $config_file->spurt($config_content); + + Lufi::DB::Slice->new(app => $m)->delete_all; + Lufi::DB::File->new(app => $m)->delete_all; + + $t = Test::Mojo->new('Lufi'); + + ## Wait for short generation + sleep 5; +} diff --git a/themes/default/lib/Lufi/I18N/en.po b/themes/default/lib/Lufi/I18N/en.po index cf37d06..384ee9e 100644 --- a/themes/default/lib/Lufi/I18N/en.po +++ b/themes/default/lib/Lufi/I18N/en.po @@ -138,15 +138,15 @@ msgstr "Copy all links to clipboard" msgid "Copy to clipboard" msgstr "Copy to clipboard" -#: lib/Lufi/Controller/Files.pm:507 +#: lib/Lufi/Controller/Files.pm:502 msgid "Could not delete the file. You are not authenticated." msgstr "Could not delete the file. You are not authenticated." -#: lib/Lufi/Controller/Files.pm:489 +#: lib/Lufi/Controller/Files.pm:484 msgid "Could not find the file. Are you sure of the URL and the token?" msgstr "Could not find the file. Are you sure of the URL and the token?" -#: lib/Lufi/Controller/Files.pm:400 +#: lib/Lufi/Controller/Files.pm:395 msgid "Could not find the file. Are you sure of the URL?" msgstr "Could not find the file. Are you sure of the URL?" @@ -222,15 +222,15 @@ msgstr "Emails" msgid "Encrypting part XX1 of XX2" msgstr "Encrypting part XX1 of XX2" -#: lib/Lufi/Controller/Files.pm:289 +#: lib/Lufi/Controller/Files.pm:284 msgid "Error: the file existed but was deleted." msgstr "Error: the file existed but was deleted." -#: lib/Lufi/Controller/Files.pm:369 +#: lib/Lufi/Controller/Files.pm:364 msgid "Error: the file has not been sent entirely." msgstr "Error: the file has not been sent entirely." -#: lib/Lufi/Controller/Files.pm:379 +#: lib/Lufi/Controller/Files.pm:374 msgid "Error: unable to find the file. Are you sure of your URL?" msgstr "Error: unable to find the file. Are you sure of your URL?" @@ -250,7 +250,7 @@ msgstr "Expires at" msgid "Export localStorage data" msgstr "Export localStorage data" -#: lib/Lufi/Controller/Files.pm:471 +#: lib/Lufi/Controller/Files.pm:466 msgid "File deleted" msgstr "File deleted" @@ -436,7 +436,7 @@ msgid "Name of the zip file" msgstr "Name of the zip file" #. (format_bytes($json->{size}) -#: lib/Lufi/Controller/Files.pm:108 +#: lib/Lufi/Controller/Files.pm:109 msgid "No enough space available on the server for this file (size: %1)." msgstr "No enough space available on the server for this file (size: %1)." @@ -551,7 +551,7 @@ msgid "Sorry, your invitation has expired or has been deleted." msgstr "Sorry, your invitation has expired or has been deleted." #. ($invit->ldap_user_mail) -#: lib/Lufi/Controller/Files.pm:122 +#: lib/Lufi/Controller/Files.pm:123 msgid "Sorry, your invitation has expired or has been deleted. Please contact %1 to have another invitation." msgstr "Sorry, your invitation has expired or has been deleted. Please contact %1 to have another invitation." @@ -585,7 +585,7 @@ msgstr "The email subject can't be empty." msgid "The expiration delay (%1) is not between 1 and %2 days." msgstr "The expiration delay (%1) is not between 1 and %2 days." -#: lib/Lufi/Controller/Files.pm:468 +#: lib/Lufi/Controller/Files.pm:463 msgid "The file has already been deleted" msgstr "The file has already been deleted" @@ -640,11 +640,11 @@ msgstr "The mail has been sent." msgid "The original (and only for now) author is Luc Didry." msgstr "The original (and only for now) author is Luc Didry." -#: lib/Lufi/Controller/Files.pm:236 +#: lib/Lufi/Controller/Files.pm:231 msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator." msgstr "The server was unable to find the file record to add your file part to. Please, contact the administrator." -#: lib/Lufi/Controller/Files.pm:295 +#: lib/Lufi/Controller/Files.pm:290 msgid "This file has been deactivated by the admins. Contact them to know why." msgstr "This file has been deactivated by the admins. Contact them to know why." @@ -674,17 +674,17 @@ msgid "Unable to copy the link(s) to your clipboard" msgstr "Unable to copy the link(s) to your clipboard" #. ($short) -#: lib/Lufi/Controller/Files.pm:439 +#: lib/Lufi/Controller/Files.pm:434 msgid "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage." msgstr "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage." #. ($short) -#: lib/Lufi/Controller/Files.pm:429 +#: lib/Lufi/Controller/Files.pm:424 msgid "Unable to get counter for %1. The token is invalid." msgstr "Unable to get counter for %1. The token is invalid." #. ($short) -#: lib/Lufi/Controller/Files.pm:449 +#: lib/Lufi/Controller/Files.pm:444 msgid "Unable to get counter for %1. You are not authenticated." msgstr "Unable to get counter for %1. You are not authenticated." @@ -769,7 +769,7 @@ msgstr "Your browser does not have enough entropy to generate a strong encryptio msgid "Your file is too big: %1 (maximum size allowed: %2)" msgstr "Your file is too big: %1 (maximum size allowed: %2)" -#: lib/Lufi/Controller/Files.pm:351 +#: lib/Lufi/Controller/Files.pm:346 msgid "Your password is not valid. Please refresh the page to retry." msgstr "Your password is not valid. Please refresh the page to retry." diff --git a/themes/default/lib/Lufi/I18N/lufi.pot b/themes/default/lib/Lufi/I18N/lufi.pot index c55bda4..2d76014 100644 --- a/themes/default/lib/Lufi/I18N/lufi.pot +++ b/themes/default/lib/Lufi/I18N/lufi.pot @@ -138,15 +138,15 @@ msgstr "" msgid "Copy to clipboard" msgstr "" -#: lib/Lufi/Controller/Files.pm:507 +#: lib/Lufi/Controller/Files.pm:502 msgid "Could not delete the file. You are not authenticated." msgstr "" -#: lib/Lufi/Controller/Files.pm:489 +#: lib/Lufi/Controller/Files.pm:484 msgid "Could not find the file. Are you sure of the URL and the token?" msgstr "" -#: lib/Lufi/Controller/Files.pm:400 +#: lib/Lufi/Controller/Files.pm:395 msgid "Could not find the file. Are you sure of the URL?" msgstr "" @@ -222,15 +222,15 @@ msgstr "" msgid "Encrypting part XX1 of XX2" msgstr "" -#: lib/Lufi/Controller/Files.pm:289 +#: lib/Lufi/Controller/Files.pm:284 msgid "Error: the file existed but was deleted." msgstr "" -#: lib/Lufi/Controller/Files.pm:369 +#: lib/Lufi/Controller/Files.pm:364 msgid "Error: the file has not been sent entirely." msgstr "" -#: lib/Lufi/Controller/Files.pm:379 +#: lib/Lufi/Controller/Files.pm:374 msgid "Error: unable to find the file. Are you sure of your URL?" msgstr "" @@ -250,7 +250,7 @@ msgstr "" msgid "Export localStorage data" msgstr "" -#: lib/Lufi/Controller/Files.pm:471 +#: lib/Lufi/Controller/Files.pm:466 msgid "File deleted" msgstr "" @@ -436,7 +436,7 @@ msgid "Name of the zip file" msgstr "" #. (format_bytes($json->{size}) -#: lib/Lufi/Controller/Files.pm:108 +#: lib/Lufi/Controller/Files.pm:109 msgid "No enough space available on the server for this file (size: %1)." msgstr "" @@ -551,7 +551,7 @@ msgid "Sorry, your invitation has expired or has been deleted." msgstr "" #. ($invit->ldap_user_mail) -#: lib/Lufi/Controller/Files.pm:122 +#: lib/Lufi/Controller/Files.pm:123 msgid "Sorry, your invitation has expired or has been deleted. Please contact %1 to have another invitation." msgstr "" @@ -585,7 +585,7 @@ msgstr "" msgid "The expiration delay (%1) is not between 1 and %2 days." msgstr "" -#: lib/Lufi/Controller/Files.pm:468 +#: lib/Lufi/Controller/Files.pm:463 msgid "The file has already been deleted" msgstr "" @@ -640,11 +640,11 @@ msgstr "" msgid "The original (and only for now) author is Luc Didry." msgstr "" -#: lib/Lufi/Controller/Files.pm:236 +#: lib/Lufi/Controller/Files.pm:231 msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator." msgstr "" -#: lib/Lufi/Controller/Files.pm:295 +#: lib/Lufi/Controller/Files.pm:290 msgid "This file has been deactivated by the admins. Contact them to know why." msgstr "" @@ -674,17 +674,17 @@ msgid "Unable to copy the link(s) to your clipboard" msgstr "" #. ($short) -#: lib/Lufi/Controller/Files.pm:439 +#: lib/Lufi/Controller/Files.pm:434 msgid "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage." msgstr "" #. ($short) -#: lib/Lufi/Controller/Files.pm:429 +#: lib/Lufi/Controller/Files.pm:424 msgid "Unable to get counter for %1. The token is invalid." msgstr "" #. ($short) -#: lib/Lufi/Controller/Files.pm:449 +#: lib/Lufi/Controller/Files.pm:444 msgid "Unable to get counter for %1. You are not authenticated." msgstr "" @@ -769,7 +769,7 @@ msgstr "" msgid "Your file is too big: %1 (maximum size allowed: %2)" msgstr "" -#: lib/Lufi/Controller/Files.pm:351 +#: lib/Lufi/Controller/Files.pm:346 msgid "Your password is not valid. Please refresh the page to retry." msgstr "" diff --git a/utilities/migrations/mysql.sql b/utilities/migrations/mysql.sql index e9a8ebb..31a3237 100644 --- a/utilities/migrations/mysql.sql +++ b/utilities/migrations/mysql.sql @@ -51,3 +51,7 @@ DROP TABLE invitations; ALTER TABLE files MODIFY filesize bigint; -- 4 down ALTER TABLE files MODIFY filesize integer; +-- 5 up +ALTER TABLE slices MODIFY path varchar(255); +-- 5 down +ALTER TABLE slices MODIFY path varchar(255) unique NOT NULL; diff --git a/utilities/migrations/pg.sql b/utilities/migrations/pg.sql index 28c8c03..8083c23 100644 --- a/utilities/migrations/pg.sql +++ b/utilities/migrations/pg.sql @@ -54,3 +54,9 @@ DROP TABLE invitations; ALTER TABLE files ALTER COLUMN filesize TYPE bigint; -- 5 down ALTER TABLE files ALTER COLUMN filesize TYPE integer; +-- 6 up +ALTER TABLE slices ALTER COLUMN path DROP NOT NULL; +ALTER TABLE slices DROP CONSTRAINT slices_path_key; +-- 6 down +ALTER TABLE slices ADD CONSTRAINT slices_path_key UNIQUE (path) ; +ALTER TABLE slices ALTER COLUMN path SET NOT NULL;