From 9c054fe79fce1ce28d758ca287e98caa30e6e3ac Mon Sep 17 00:00:00 2001 From: hedii Date: Mon, 12 Oct 2020 13:53:15 +0200 Subject: [PATCH] Add support for temporary urls --- .travis.yml | 25 ++-- README.md | 33 +++++- phpunit.xml.dist | 1 + src/OvhSwiftStorageAdapter.php | 72 +++++++++-- src/OvhSwiftStorageServiceProvider.php | 28 +++-- tests/OvhSwiftStorageTest.php | 158 ------------------------- tests/PrivateContainerTest.php | 101 ++++++++++++++++ tests/PublicContainerTest.php | 96 +++++++++++++++ tests/TestCase.php | 63 ++++++++++ 9 files changed, 382 insertions(+), 195 deletions(-) delete mode 100644 tests/OvhSwiftStorageTest.php create mode 100644 tests/PrivateContainerTest.php create mode 100644 tests/PublicContainerTest.php create mode 100644 tests/TestCase.php diff --git a/.travis.yml b/.travis.yml index e0b02f1..7b79c3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,21 @@ language: php php: -- 7.4 + - 7.4 before_script: -- composer self-update -- composer install + - composer self-update + - composer install script: -- composer test + - composer test matrix: fast_finish: true env: global: - - secure: ggxLIhqoMh6KmERMgFoxuP8S4Ne+XRw4ieiRO1dr6VBKsXpSymgAUTBsld/L9HsXA5rlqCi2aboxwlHXSX/DZMmRHN8+ofQfQD/3wkMDw2OV3YOcMABQ8Dua74uygSLQdv+zRsCH2jhf1qafGOI8jTv5smGM49Pr/R/Tne0xrZQhA9L68tqafNRfxWxtxAmtjloClNJcl2p/MEVscdczeb319I/8tlac3zSITNxB724/+2akxvUUhMmr0Yjy5Hem4W+DHWGT/EnExb+6rwAN1icZb+RHeBIpTGFrFlhQ1JM7ntc/3QVhFkZhEYrkdTwCPseZSNr+13HaupDR9M5fjCu9MM/Qq8M+yU9rtlJWQ+FdJYYvHVL91GIYH8pUn4oYph0t6ncFBCx7y5QWN27fG/ey2JSiY7rwxVb+PCfLdI9ljgJ14Zy5QfszjrIcy6iCXdTiYIaWSn//iFPAwql6lrn49kHIv5CbNv9Eo+XMUpW2yUEh79iSinUtAo8yyh7eipEoo1O7W5msDAX+x+S2Kdp2+RX3laAQj2O2YDYyvCncPx4SZPSDLsWDglWAOvhjh1nMOa8mAEYyyQ70CRnx1V9d1wBKQirICzsnGGNl6wfNSmhxMh7tA2hBFLPHKIRvtf8GQcgMo29Zpa2ko37bzdAOIpiGoJOA0nMmutjQqFk= - - secure: Mmj7auE+Ate7tOnpkWNF8hE63Bg9RKs0m5b/ilL3HXAfsCciL7BHnGrBre7bH9tDnzHhVYa3nFyzPRbiC8mkmviu4JzS278sRjfjTWSSgO9u9uXkRYa5HIHxgXsp14uk/yhHA4aqgfELsdHFBw0/sJV6JklLoOk/UpWiuugGoB9hzNbS843eRtRxK5nVE4GncS3QcXTpJPr9GbnjWEELm3YH7mEbFFYdZnp/bZEp1Ia8IORO4Vw+zVy41u5a/euHA8goBdvHSkrSc276p7wMKbYXxga7yDQrk//x2HEnRPWwH+EMSWTm4fBdcStYoygmasAr2SJR+h9YYqIdsh8PCx7o+2zj5ipTI5TPIxa8pbL8Y8wmoOlKanuJB0GmGZ5xZECLkb6t1ZknnlIXgzXcXtbiOaRQ9csPyNyJH2XllPJOBEMmr3IeWz/5moo7vkhEUPopVSOdm6pC2FMILNfBTHK6RSJ4l6tBMyRTqHZpn2STrZY4abQgUXPqVuq8e6AMrAy1226mxev7gWvUD7zxt2RJ+czgcjrWyv9Ij1EJGV4r/pxwT3Z/Hr7kBIqm9rJ7ZxMIypnaChDOcRS4U4x6Kx1nHkQPyOtm2R4xe+RgT/bHJps0HpIS7VdYcSSsNCd+KxfwUZ62WfAk3G9v6fpBq9X9DeAqaDSRJ05Eho/tZFs= - - secure: j6G692KjdmFCr7B4GGpsTRPJYkrTBXtDPjvPXxINquDUHT+PJf4JFPsm4gEM7givEUioimgodSYir8xFQel1ghZsjQqAT4hRsKWqqCPglhnvjacT9qntQXtNrweHX3tUDEqjgjz3B7s7pGn46D7FNuZ5ikNfagrJuOyTwLGIl4GWWvD0vRz8VGHaRoWgmM56Ny5NiZiqgnvKYTuxrz8pDWvYU5fIgnLYkADhl3erPGBsQypIfEn8gAm0pjHXLqOeg0/t6K/2QG1KIY5rLgSOKo66w4B+TQItTscQsQHPagDL7xjDksGpiky4+wZ4nY571r+UwmF3oKPoIkkFPFi4mW+vOcP6c8pR/NH57CWmG/+3GsahHKla664YnBWG45lTZexqkDpOV2cXXJNS+jU7xkiDbITMnAUs5qsZwIc+jOsopX/mL/ZOE08XOQO+jAXqYn0MWHxebSCwuz3hYzWxVZwJNww6oUOAb17gR8FVX2Vu6HeLa/ygeZ2i8QR8oaZCzCg9RN06TcoqqmeYIJvCLGmgu2nJYm39fAfzMDdmlLuCgEbKCZIAXh5hZe2KckFgG7sDPP9iNIOGN9sOgXcVrQl1D9wPF2auj5ZSMy7zfsl8GQmMacWYGLbXkLUJ0Ra+oC83s8XUq4zko7nFBDYuwBp5Jn1ESblPkKRTZZeF/MU= - - secure: gQGTnHYYW+N0gg73+klfVezHw/hQ+1VzQQv52kMAZG5MdLspbmUStB7U6r4r5iMco516XBQG3aW3XnuUjweVqCFtTZDyWhLlE/etuxOK/5MsBzM4WOn+ZmLMEIiDHXkBmG1184IygCdJOLjExsLHkehUiufeP8WtMO5bsh8ZFHqx+HOJQC0B9P9up2BIpZSBFv3M0BRbrUbmmntxM/NWFr2uFxoIM2WnUWAyFjetgub7IGVFAre3mMRelocxRxHqwTftUMBbEOpRqUwsJ/ZHXQtJ0leWnKoI5tcbAivKqgDQcZsXMmpYxmMEb70o9ahTE1YmiodPxmEGMPh6bAjcTetSuP45koQnnt4HLCqtTq7WXX8TNo12lrV7u+i6PvuVs/2L1Nb7CoHK1z4IBy9LzEGR6it4s2bwwROsy86XAELGWd7xdK+D3C7mJ4WxdvPB2odeogugxFNlkSBgiDseY/grf1lNqjs1A8Efr+WNYMJ4kG+GozAEhYLzErO9hwrYO7WA2Tu+qPw6R0QY7J/6SWQVrK5Ri6ch8Ml3umO8EFilj6e/XkV7om6L73KXskukpWNufIiLbWxxnKIwwVZL7l+vM38hPdIyyaK3Y49AivPe8A0KRrmAffXTAE+xrNrDOO1MEonRPY8SMSeebSfxUMgYkF60rKCNC+GWgf1Ri3c= - - secure: OdJqvuqIxaAUp/xJMW9hOK0rwlHbZZkZp+KdOemXbBYX7etfwLAYDhQc0t78eFT9QVnBICE/jDKaU5OGu0de7OUB8QmGGhuNLWCBrcnDv/ONHWjum7Y9ieTRO/CRbEJBh2FTdMGgcFXkc0oHL5OS5vayC9SZnzUiw+pDQM2x5YuHETCPvbjimzu0jAl6omIlLHSTPU6K2nbjiBpo6E2aYAQ3VpVTBYP8A83REo4v5y1xuwSEJn/zgzkIOfPXv1cLBGkjDCQs6zonfiO72pE+wHGdUb+Rp0ZT9MJgoImudeF1tpZm/Ku7Prn3OgBk6RHxKc70ykFF306kyxL+lSQtN2lAzFKbNiXiMF1sQzZm6WwqmO/DZ92/9BqDR974eLyrLAz28HeLAfyy/s7KX2uUkNYdEylKO9Id/W6wiPKEQg6+TIIn6tKhquYkqIBUwLHZV270HsZJUs7+830iA+1O6ccKThD1TbxHIdr43751QXu2JM2GRBQlGKHEc+rbZ0vd/o+faWRtF5V8TD7yuPmrVieqjbKQggzpMGuPYdSWstvd/fMmKDohITo8euyC16aU1iBbwoFpcBTynfR1ZkQeGS/FQXB6boe68UENh27Ade29MrPy8Jw5QeKDIDgn8vDZtvX4r/AuMfFm93hMkwxvCJN9GC6AB/0qPy/RhJHo3v0= - - secure: QlgVcuzAuFnQLVTaxNXen1pBAk0QrsYXUdT3+gWd8U1Iv4lvos2NG06cl/8kRk2wM80U5aNZDyabkSSkH+SwH3IfqNMXkIBnFi2CtQY/wLAxWIDRyEn4sG3SkKuY8nDIgQ//Sy2FRPJErD66N7cOf/HWzoKhDK3SsmG8TesYXtlHyVc7dpXXc7XGAWXaqr+6PrP/uZ0uT8E1s8EnHS25E01jff4rGAM7RsWszb5CePFKeNqEPZBAORnMRdEWVoelbj++EXN9AOhKhwP3CjVN9ZY13my/pB4yYjIiXVQr/YemVm1heROA3kJjxB1e8NLe6XJig/RYXJpOwLBp3y1d5RxTLpoFlQCGQKP647KUPBE1bhgXWQrAnIkwLzJSIl0PeXT3vhSIt7rLxcKEbVBYTUp+Q+L1UlVpcrXQ9DK4d3Q0tno63mtiWl/bgh558Sy14iQKb9h4jlOfxYG6uhPezPleqgvFBhwJQ0esEPgawJ/n52EFs6nj6ZflowW1ljHV0+BYP7kpcyn0thMuxysmqekoe9IzoV/OwDcPCMzl9n8oQ41Hp2AcmQf7f9Ol0R5kypGqIqQZ3uoKHoC4ZcZf6qIGld48Pb9et1OGL49sP1ikV7Qzy63BEJ47LsHhljfowPV6fa3MiFzHc8XcDXfr+RKYGS4gByHJW4jpaZffdMU= - - secure: AFoM4raIEBu3gM4sj8cboEFvvDpgpzl8STDOrp8mB0Qisepg1NQHKIzpNTXbMC/bNF9RWGlIn2qYah2xrMEnlYO1xYJ1JyjaqUOwjQxiXKu3VEwojQvyljSFVVLms2TQ0o3DLsY3YuuOnygJ9rYcTMvj4NiDf4PuPCGIpAYbhImirylFtBzgqblWt5albq2WgL1SYsLVjQ9MziaKRiVpclZPqeTlezNqD2co+h6YRZiVnL43MN1jlRsfPo8DlpetgKSLIDWM1GcToneRPYf4IJvonnmfmVdatxm5GVD3d7MHKun1gRLK+Ru9GWdoQDoFMAwCchnugtNd96DcgHtZbGTDoWKQEozSMdG65rs3EEzeWHFMVdrAGCRMpvZU3jsr6xvbuZIIEpT0nEztoAwlIcMYBqSTZ19Eywa/XF09H9/n1VT3X5JzTcJIliQpPTsAt65VPQDZUCGkSYZmtrlVD1I/+2itFezRsMGUkjynvEUxt+UEIfdE49vUZmUw59paNo6PHbmlZzvlgIHLC9UiiPb13PUPFj7o+gmQT9+DR8+mbA3TZgVyjZfr3SjAonb1cNbL2HXHSRcOLl9B4y5u7VMEBvm8SQr/ZOLGMsRzNsVqVG++QiebzBXoZ+Fru1gWiVGw+JhmAIDp++w1OzaJYaBwcCBZeQK1/nWccRJnA4A= - - secure: Od1fAKvYsA8wGzbijACiv0iG2QkgDzEpSfioK6bP1eJeeqsuzK/sZI8fT/xmThjRVt0rAr/nIQASgr/4eKinAJVhFHOxWqJSrMJEkY8pbwotBJHk5psYWqf6Se7as7o7xOLGeJNMylxQkUGN5ZnmSyL4xQsuapLcB5tm/ZAmWo6TZxKfJE4VhM/uhYzSVNojO6vXjYXJCkL74lEO7yeFuu0m9GOmXdInq35LFV49L9DTe0//B4QB91kuMFSC5uT54dC/uwXwuAt6HWbIElahTNOUTfVXSZlVMhVWPsVQpbXa8KV6HrgLr3lCxi4VGT0CckmxjDjPiIvXO7K7o/9Kd7C4HhhHjyjDiowBWtQayK4UOBhzaWXyfiUCJX22RJRJ6lPREAH3fETVM1GE88OoDUmt+6/KOQLcIIGJyCV9mDAr7R4rlhNNpOkmaeoH6ONq/AgKqiFXePVlo4ZxhQdmmdPzGWNwhyB49DFTgTehD6hkt4Yh54UgpHCrwc4eI1LV5FPuuL1WSoHvFuThK8Rf7HbGmneBs/QQ+wFEGVqs3UXmBud9JfTjvAqu0IineX8x56+m97yPuHPZlqpm4e51BCakZW/a/noGrzkyET1+9dvE8l2XqPgfZztZyjCYBEzXZPSXIlGecdVnwo1wHr9pg5Ojx6bgk7poVmrEjgVKzKQ= + - secure: ggxLIhqoMh6KmERMgFoxuP8S4Ne+XRw4ieiRO1dr6VBKsXpSymgAUTBsld/L9HsXA5rlqCi2aboxwlHXSX/DZMmRHN8+ofQfQD/3wkMDw2OV3YOcMABQ8Dua74uygSLQdv+zRsCH2jhf1qafGOI8jTv5smGM49Pr/R/Tne0xrZQhA9L68tqafNRfxWxtxAmtjloClNJcl2p/MEVscdczeb319I/8tlac3zSITNxB724/+2akxvUUhMmr0Yjy5Hem4W+DHWGT/EnExb+6rwAN1icZb+RHeBIpTGFrFlhQ1JM7ntc/3QVhFkZhEYrkdTwCPseZSNr+13HaupDR9M5fjCu9MM/Qq8M+yU9rtlJWQ+FdJYYvHVL91GIYH8pUn4oYph0t6ncFBCx7y5QWN27fG/ey2JSiY7rwxVb+PCfLdI9ljgJ14Zy5QfszjrIcy6iCXdTiYIaWSn//iFPAwql6lrn49kHIv5CbNv9Eo+XMUpW2yUEh79iSinUtAo8yyh7eipEoo1O7W5msDAX+x+S2Kdp2+RX3laAQj2O2YDYyvCncPx4SZPSDLsWDglWAOvhjh1nMOa8mAEYyyQ70CRnx1V9d1wBKQirICzsnGGNl6wfNSmhxMh7tA2hBFLPHKIRvtf8GQcgMo29Zpa2ko37bzdAOIpiGoJOA0nMmutjQqFk= + - secure: Mmj7auE+Ate7tOnpkWNF8hE63Bg9RKs0m5b/ilL3HXAfsCciL7BHnGrBre7bH9tDnzHhVYa3nFyzPRbiC8mkmviu4JzS278sRjfjTWSSgO9u9uXkRYa5HIHxgXsp14uk/yhHA4aqgfELsdHFBw0/sJV6JklLoOk/UpWiuugGoB9hzNbS843eRtRxK5nVE4GncS3QcXTpJPr9GbnjWEELm3YH7mEbFFYdZnp/bZEp1Ia8IORO4Vw+zVy41u5a/euHA8goBdvHSkrSc276p7wMKbYXxga7yDQrk//x2HEnRPWwH+EMSWTm4fBdcStYoygmasAr2SJR+h9YYqIdsh8PCx7o+2zj5ipTI5TPIxa8pbL8Y8wmoOlKanuJB0GmGZ5xZECLkb6t1ZknnlIXgzXcXtbiOaRQ9csPyNyJH2XllPJOBEMmr3IeWz/5moo7vkhEUPopVSOdm6pC2FMILNfBTHK6RSJ4l6tBMyRTqHZpn2STrZY4abQgUXPqVuq8e6AMrAy1226mxev7gWvUD7zxt2RJ+czgcjrWyv9Ij1EJGV4r/pxwT3Z/Hr7kBIqm9rJ7ZxMIypnaChDOcRS4U4x6Kx1nHkQPyOtm2R4xe+RgT/bHJps0HpIS7VdYcSSsNCd+KxfwUZ62WfAk3G9v6fpBq9X9DeAqaDSRJ05Eho/tZFs= + - secure: j6G692KjdmFCr7B4GGpsTRPJYkrTBXtDPjvPXxINquDUHT+PJf4JFPsm4gEM7givEUioimgodSYir8xFQel1ghZsjQqAT4hRsKWqqCPglhnvjacT9qntQXtNrweHX3tUDEqjgjz3B7s7pGn46D7FNuZ5ikNfagrJuOyTwLGIl4GWWvD0vRz8VGHaRoWgmM56Ny5NiZiqgnvKYTuxrz8pDWvYU5fIgnLYkADhl3erPGBsQypIfEn8gAm0pjHXLqOeg0/t6K/2QG1KIY5rLgSOKo66w4B+TQItTscQsQHPagDL7xjDksGpiky4+wZ4nY571r+UwmF3oKPoIkkFPFi4mW+vOcP6c8pR/NH57CWmG/+3GsahHKla664YnBWG45lTZexqkDpOV2cXXJNS+jU7xkiDbITMnAUs5qsZwIc+jOsopX/mL/ZOE08XOQO+jAXqYn0MWHxebSCwuz3hYzWxVZwJNww6oUOAb17gR8FVX2Vu6HeLa/ygeZ2i8QR8oaZCzCg9RN06TcoqqmeYIJvCLGmgu2nJYm39fAfzMDdmlLuCgEbKCZIAXh5hZe2KckFgG7sDPP9iNIOGN9sOgXcVrQl1D9wPF2auj5ZSMy7zfsl8GQmMacWYGLbXkLUJ0Ra+oC83s8XUq4zko7nFBDYuwBp5Jn1ESblPkKRTZZeF/MU= + - secure: gQGTnHYYW+N0gg73+klfVezHw/hQ+1VzQQv52kMAZG5MdLspbmUStB7U6r4r5iMco516XBQG3aW3XnuUjweVqCFtTZDyWhLlE/etuxOK/5MsBzM4WOn+ZmLMEIiDHXkBmG1184IygCdJOLjExsLHkehUiufeP8WtMO5bsh8ZFHqx+HOJQC0B9P9up2BIpZSBFv3M0BRbrUbmmntxM/NWFr2uFxoIM2WnUWAyFjetgub7IGVFAre3mMRelocxRxHqwTftUMBbEOpRqUwsJ/ZHXQtJ0leWnKoI5tcbAivKqgDQcZsXMmpYxmMEb70o9ahTE1YmiodPxmEGMPh6bAjcTetSuP45koQnnt4HLCqtTq7WXX8TNo12lrV7u+i6PvuVs/2L1Nb7CoHK1z4IBy9LzEGR6it4s2bwwROsy86XAELGWd7xdK+D3C7mJ4WxdvPB2odeogugxFNlkSBgiDseY/grf1lNqjs1A8Efr+WNYMJ4kG+GozAEhYLzErO9hwrYO7WA2Tu+qPw6R0QY7J/6SWQVrK5Ri6ch8Ml3umO8EFilj6e/XkV7om6L73KXskukpWNufIiLbWxxnKIwwVZL7l+vM38hPdIyyaK3Y49AivPe8A0KRrmAffXTAE+xrNrDOO1MEonRPY8SMSeebSfxUMgYkF60rKCNC+GWgf1Ri3c= + - secure: OdJqvuqIxaAUp/xJMW9hOK0rwlHbZZkZp+KdOemXbBYX7etfwLAYDhQc0t78eFT9QVnBICE/jDKaU5OGu0de7OUB8QmGGhuNLWCBrcnDv/ONHWjum7Y9ieTRO/CRbEJBh2FTdMGgcFXkc0oHL5OS5vayC9SZnzUiw+pDQM2x5YuHETCPvbjimzu0jAl6omIlLHSTPU6K2nbjiBpo6E2aYAQ3VpVTBYP8A83REo4v5y1xuwSEJn/zgzkIOfPXv1cLBGkjDCQs6zonfiO72pE+wHGdUb+Rp0ZT9MJgoImudeF1tpZm/Ku7Prn3OgBk6RHxKc70ykFF306kyxL+lSQtN2lAzFKbNiXiMF1sQzZm6WwqmO/DZ92/9BqDR974eLyrLAz28HeLAfyy/s7KX2uUkNYdEylKO9Id/W6wiPKEQg6+TIIn6tKhquYkqIBUwLHZV270HsZJUs7+830iA+1O6ccKThD1TbxHIdr43751QXu2JM2GRBQlGKHEc+rbZ0vd/o+faWRtF5V8TD7yuPmrVieqjbKQggzpMGuPYdSWstvd/fMmKDohITo8euyC16aU1iBbwoFpcBTynfR1ZkQeGS/FQXB6boe68UENh27Ade29MrPy8Jw5QeKDIDgn8vDZtvX4r/AuMfFm93hMkwxvCJN9GC6AB/0qPy/RhJHo3v0= + - secure: QlgVcuzAuFnQLVTaxNXen1pBAk0QrsYXUdT3+gWd8U1Iv4lvos2NG06cl/8kRk2wM80U5aNZDyabkSSkH+SwH3IfqNMXkIBnFi2CtQY/wLAxWIDRyEn4sG3SkKuY8nDIgQ//Sy2FRPJErD66N7cOf/HWzoKhDK3SsmG8TesYXtlHyVc7dpXXc7XGAWXaqr+6PrP/uZ0uT8E1s8EnHS25E01jff4rGAM7RsWszb5CePFKeNqEPZBAORnMRdEWVoelbj++EXN9AOhKhwP3CjVN9ZY13my/pB4yYjIiXVQr/YemVm1heROA3kJjxB1e8NLe6XJig/RYXJpOwLBp3y1d5RxTLpoFlQCGQKP647KUPBE1bhgXWQrAnIkwLzJSIl0PeXT3vhSIt7rLxcKEbVBYTUp+Q+L1UlVpcrXQ9DK4d3Q0tno63mtiWl/bgh558Sy14iQKb9h4jlOfxYG6uhPezPleqgvFBhwJQ0esEPgawJ/n52EFs6nj6ZflowW1ljHV0+BYP7kpcyn0thMuxysmqekoe9IzoV/OwDcPCMzl9n8oQ41Hp2AcmQf7f9Ol0R5kypGqIqQZ3uoKHoC4ZcZf6qIGld48Pb9et1OGL49sP1ikV7Qzy63BEJ47LsHhljfowPV6fa3MiFzHc8XcDXfr+RKYGS4gByHJW4jpaZffdMU= + - secure: AFoM4raIEBu3gM4sj8cboEFvvDpgpzl8STDOrp8mB0Qisepg1NQHKIzpNTXbMC/bNF9RWGlIn2qYah2xrMEnlYO1xYJ1JyjaqUOwjQxiXKu3VEwojQvyljSFVVLms2TQ0o3DLsY3YuuOnygJ9rYcTMvj4NiDf4PuPCGIpAYbhImirylFtBzgqblWt5albq2WgL1SYsLVjQ9MziaKRiVpclZPqeTlezNqD2co+h6YRZiVnL43MN1jlRsfPo8DlpetgKSLIDWM1GcToneRPYf4IJvonnmfmVdatxm5GVD3d7MHKun1gRLK+Ru9GWdoQDoFMAwCchnugtNd96DcgHtZbGTDoWKQEozSMdG65rs3EEzeWHFMVdrAGCRMpvZU3jsr6xvbuZIIEpT0nEztoAwlIcMYBqSTZ19Eywa/XF09H9/n1VT3X5JzTcJIliQpPTsAt65VPQDZUCGkSYZmtrlVD1I/+2itFezRsMGUkjynvEUxt+UEIfdE49vUZmUw59paNo6PHbmlZzvlgIHLC9UiiPb13PUPFj7o+gmQT9+DR8+mbA3TZgVyjZfr3SjAonb1cNbL2HXHSRcOLl9B4y5u7VMEBvm8SQr/ZOLGMsRzNsVqVG++QiebzBXoZ+Fru1gWiVGw+JhmAIDp++w1OzaJYaBwcCBZeQK1/nWccRJnA4A= + - secure: Od1fAKvYsA8wGzbijACiv0iG2QkgDzEpSfioK6bP1eJeeqsuzK/sZI8fT/xmThjRVt0rAr/nIQASgr/4eKinAJVhFHOxWqJSrMJEkY8pbwotBJHk5psYWqf6Se7as7o7xOLGeJNMylxQkUGN5ZnmSyL4xQsuapLcB5tm/ZAmWo6TZxKfJE4VhM/uhYzSVNojO6vXjYXJCkL74lEO7yeFuu0m9GOmXdInq35LFV49L9DTe0//B4QB91kuMFSC5uT54dC/uwXwuAt6HWbIElahTNOUTfVXSZlVMhVWPsVQpbXa8KV6HrgLr3lCxi4VGT0CckmxjDjPiIvXO7K7o/9Kd7C4HhhHjyjDiowBWtQayK4UOBhzaWXyfiUCJX22RJRJ6lPREAH3fETVM1GE88OoDUmt+6/KOQLcIIGJyCV9mDAr7R4rlhNNpOkmaeoH6ONq/AgKqiFXePVlo4ZxhQdmmdPzGWNwhyB49DFTgTehD6hkt4Yh54UgpHCrwc4eI1LV5FPuuL1WSoHvFuThK8Rf7HbGmneBs/QQ+wFEGVqs3UXmBud9JfTjvAqu0IineX8x56+m97yPuHPZlqpm4e51BCakZW/a/noGrzkyET1+9dvE8l2XqPgfZztZyjCYBEzXZPSXIlGecdVnwo1wHr9pg5Ojx6bgk7poVmrEjgVKzKQ= + - secure: kFTjTSf8AcTw2hc8IMA5ENbemfwbsPzegwS3zrP7jW+c/8WES7iFyloTvVwD4zta4V4B3Q+8ra7zW+Zkfpfh12AOyIyTws5Q+h7qXxNsAXyp2j+eMhoF1Ap7y1T73Ja1f0nCocrrWMG7Jku5pG2wGf5hfHm5KYkWmHeuLfZh/Ag5j7/y13mz9UWka8WtLmdBT0m1VLNoJIZPSboizPNvoMksJdoD90yZUB7X9aDU1YaTwdQghrwVeHYU5CDhePrGAJgeJEDN844JY6+pjg8PIUyk+fZ3wc6wcim1fmqdjtJLVBa7xygKpteV6I66zB12SCHUBigEW35jWWDp3pU/dxpf9XmoY2bT5BDCcA1ZjtY7aDJTP+uT2qhf+Um67ILDxUUH2hhP4uKjVe/DQra78ZRVLlP0CGIpSDUBE/JZ60dLUda24s5cax2n7fdi7qeWv1627xa+060zrQ+8dOs6mdHJY6lZzCJM5aTph8iMfeGWnsIfbmmg1OgbX0LA3ZylJIGJbWSMg7o30/p7BwKhTI0pdz89D2k54kh1Gi9i5pCATX6yBC6V5HSHsmR41HVZA9rcyQbLRn+SAYbkTa++4Bbcjtn2bNNS2bGEM65H4uA9uQm6n5LSsfMCaFVfKpqccGCs3xBrX+tlu2xbu1iRL8ZLKl79uaKvhEpBJKU7E1I= diff --git a/README.md b/README.md index 8d5b93e..ac9fc48 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ return [ 'password' => env('OVH_SWIFT_OPENSTACK_PASSWORD'), 'visibility' => env('OVH_SWIFT_VISIBILITY', 'public'), 'publicUrl' => env('OVH_SWIFT_PUBLIC_URL'), + 'urlKey' => env('OVH_SWIFT_URL_KEY'), ], ], @@ -61,19 +62,47 @@ OVH_SWIFT_OPENSTACK_PASSWORD=xxxxxxxxxxxxxxxxxxx Once you have modified the Laravel filesystem configuration and the environment variables, you can use the new Ovh Swift storage disk [as any Laravel storage disk](https://laravel.com/docs/6.x/filesystem#obtaining-disk-instances). +### Private containers + +By default, this package assumes you are using a public Object Storage container. + +If you want to use a private container with temporary urls, you have to configure a [temporary url key](https://docs.ovh.com/ie/en/public-cloud/share_an_object_via_a_temporary_url/) and set the visibility to `private`. + +``` +OVH_SWIFT_OPENSTACK_REGION=GRA +OVH_SWIFT_OPENSTACK_PROJECT_ID=xxxxxxxxxxxxxxxxxxx +OVH_SWIFT_CONTAINER_NAME=xxxxxxxxxxxxxxxxxxx +OVH_SWIFT_OPENSTACK_USERNAME=xxxxxxxxxxxxxxxxxxx +OVH_SWIFT_OPENSTACK_PASSWORD=xxxxxxxxxxxxxxxxxxx +OVH_SWIFT_VISIBILITY=private +OVH_SWIFT_URL_KEY=xxxxxxxxxxxxxxxxxxx +``` + +Be aware you will not be able to retrieve regular urls with a private container, only temporary urls. + ### Example ```php use Illuminate\Support\Facades\Storage; Storage::disk('ovh-swift')->put('avatars/1', $fileContents); + +$url = Storage::url('avatars/1'); + +// if using private containers: +$temporaryUrl = Storage::temporaryUrl('avatars/1', now()->addMinute()); ``` ## Testing -If you want to test the package, you must create a new Ovh Object Storage container and a new Openstack user. Once it's done, copy `phpunit.xml.dist` to `phpunit.xml` and update the environment variables. +If you want to test the package, you must create a new Openstack user and two new Ovh Object Storage containers: + +- A public container named `test` +- A private container named `test-private` + +Once it's done, copy `phpunit.xml.dist` to `phpunit.xml` and update the environment variables. -Be aware that the test suite will delete all files in the container after each test. **Do not test against a production container!** +Be aware that the test suite will delete all files in the containers after each test. **Do not test against a production containers!** To start test suite, run this command: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e778314..5e9446d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,6 +17,7 @@ + --> diff --git a/src/OvhSwiftStorageAdapter.php b/src/OvhSwiftStorageAdapter.php index 852c902..d4b28c7 100644 --- a/src/OvhSwiftStorageAdapter.php +++ b/src/OvhSwiftStorageAdapter.php @@ -2,6 +2,8 @@ namespace Hedii\LaravelOvhSwiftStorage; +use DateTimeInterface; +use Illuminate\Support\Str; use Nimbusoft\Flysystem\OpenStack\SwiftAdapter; use OpenStack\Common\Transport\Utils; use OpenStack\ObjectStore\v1\Models\Container; @@ -10,22 +12,45 @@ class OvhSwiftStorageAdapter extends SwiftAdapter { /** - * The container public url. + * The container url. * - * @var null|string + * @var string */ - protected ?string $publicUrl; + protected string $containerUrl; + + /** + * The container visibility. + * + * @var string + */ + protected string $visibility; + + /** + * The url key used for temporary urls. + * + * @var string|null + */ + protected ?string $urlKey; /** * OvhSwiftStorageAdapter constructor. * * @param \OpenStack\ObjectStore\v1\Models\Container $container + * @param string $containerUrl + * @param string $visibility * @param string|null $prefix - * @param string|null $publicUrl + * @param string|null $urlKey */ - public function __construct(Container $container, ?string $prefix = null, ?string $publicUrl = null) - { - $this->publicUrl = $publicUrl; + public function __construct( + Container $container, + string $containerUrl, + string $visibility, + ?string $prefix = null, + ?string $urlKey = null + ) { + $this->containerUrl = $containerUrl; + $this->visibility = $visibility; + $this->urlKey = $urlKey; parent::__construct($container, $prefix); } @@ -35,13 +60,40 @@ public function __construct(Container $container, ?string $prefix = null, ?strin * * @param string $path * @return string + * @throws \RuntimeException */ public function getUrl(string $path): string { - if (! $this->publicUrl) { - throw new RuntimeException('This disk does not support retrieving URLs.'); + if ($this->visibility !== self::VISIBILITY_PUBLIC) { + throw new RuntimeException('This driver does not support retrieving URLs because the visibility is not public. Please use temporary URLs.'); + } + + return Utils::normalizeUrl($this->containerUrl) . $path; + } + + /** + * Get a temporary URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return string + * @throws \RuntimeException + */ + public function getTemporaryUrl(string $path, DateTimeInterface $expiration, array $options = []): string + { + if ($this->visibility !== self::VISIBILITY_PRIVATE) { + throw new RuntimeException('This driver does not support creating temporary URLs because the visibility is not private. Please use regular URLs.'); + } elseif (! $this->urlKey) { + throw new RuntimeException('This driver does not support creating temporary URLs because no temp url key has been configured.'); } - return Utils::normalizeUrl($this->publicUrl) . $path; + $expiration = $expiration->getTimestamp(); + $pathWithoutHost = Str::after($this->containerUrl, parse_url($this->containerUrl, PHP_URL_HOST)) . "/{$path}"; + $body = sprintf("%s\n%s\n%s", 'GET', $expiration, $pathWithoutHost); + $signature = hash_hmac('sha1', $body, $this->urlKey); + + return Utils::normalizeUrl($this->containerUrl) + . "{$path}?temp_url_sig={$signature}&temp_url_expires={$expiration}"; } } diff --git a/src/OvhSwiftStorageServiceProvider.php b/src/OvhSwiftStorageServiceProvider.php index 9e89633..d3cc79d 100644 --- a/src/OvhSwiftStorageServiceProvider.php +++ b/src/OvhSwiftStorageServiceProvider.php @@ -59,7 +59,13 @@ public function boot(FilesystemManager $filesystemManager, CacheRepository $cach $container = $openstack->objectStoreV1()->getContainer($config['containerName']); - $adapter = new OvhSwiftStorageAdapter($container, $config['prefix'], $options['publicUrl']); + $adapter = new OvhSwiftStorageAdapter( + $container, + $options['publicUrl'], + $config['visibility'] ?? OvhSwiftStorageAdapter::VISIBILITY_PUBLIC, + $config['prefix'] ?? null, + $config['urlKey'] ?? null + ); return new Filesystem($adapter); }); @@ -69,22 +75,18 @@ public function boot(FilesystemManager $filesystemManager, CacheRepository $cach * Get the container public url. * * @param array $config - * @return string|null + * @return string */ - private function getContainerPublicUrl(array $config): ?string + private function getContainerPublicUrl(array $config): string { - if (isset($config['visibility']) && $config['visibility'] === 'public') { - if (isset($config['publicUrl']) && $config['publicUrl']) { - $base = $config['publicUrl']; - } else { - $region = strtolower($config['region']); - - $base = "https://storage.{$region}.cloud.ovh.net/v1/AUTH_{$config['projectId']}/{$config['containerName']}"; - } + if (isset($config['publicUrl']) && $config['publicUrl']) { + $base = $config['publicUrl']; + } else { + $region = strtolower($config['region']); - return (isset($config['prefix']) && $config['prefix']) ? "{$base}/{$config['prefix']}" : $base; + $base = "https://storage.{$region}.cloud.ovh.net/v1/AUTH_{$config['projectId']}/{$config['containerName']}"; } - return null; + return (isset($config['prefix']) && $config['prefix']) ? "{$base}/{$config['prefix']}" : $base; } } diff --git a/tests/OvhSwiftStorageTest.php b/tests/OvhSwiftStorageTest.php deleted file mode 100644 index c76c877..0000000 --- a/tests/OvhSwiftStorageTest.php +++ /dev/null @@ -1,158 +0,0 @@ -set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration()); - $app['config']->set('filesystems.default', 'ovh-swift'); - } - - /** @test */ - public function it_should_put_a_file_in_the_swift_container(): void - { - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - $this->assertSame($content, file_get_contents(Storage::url($fileName))); - } - - /** @test */ - public function it_should_set_a_prefix_if_needed(): void - { - $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration(['prefix' => 'foo'])); - - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - $this->assertStringEndsWith("foo/{$fileName}", Storage::url($fileName)); - } - - /** @test */ - public function it_should_not_set_a_prefix_if_prefix_is_null(): void - { - $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration(['prefix' => null])); - - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - $this->assertStringEndsWith( - "{$this->getOvhSwiftConfiguration()['containerName']}/{$fileName}", - Storage::url($fileName) - ); - } - - /** @test */ - public function it_should_not_create_a_public_file_if_visibility_is_not_public(): void - { - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('This disk does not support retrieving URLs'); - - $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration(['visibility' => 'private'])); - - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - Storage::url($fileName); - } - - /** @test */ - public function it_should_use_a_custom_public_url_if_needed(): void - { - $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ - 'publicUrl' => 'http://foo.example.com', - 'prefix' => null - ])); - - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - $this->assertSame( - "http://foo.example.com/{$fileName}", - Storage::url($fileName) - ); - } - - /** @test */ - public function it_should_preserve_prefix_with_a_custom_public_url(): void - { - $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ - 'publicUrl' => 'http://foo.example.com', - 'prefix' => 'a-prefix' - ])); - - $fileName = $this->randomFileName(); - $content = $this->randomContent(); - - Storage::put($fileName, $content); - - $this->assertSame( - "http://foo.example.com/a-prefix/{$fileName}", - Storage::url($fileName) - ); - } - - protected function getOvhSwiftConfiguration(array $config = []): array - { - $baseConfig = [ - 'driver' => 'ovh-swift', - 'authUrl' => env('OVH_SWIFT_OPENSTACK_AUTH_URL'), - 'region' => env('OVH_SWIFT_OPENSTACK_REGION'), - 'projectId' => env('OVH_SWIFT_OPENSTACK_PROJECT_ID'), - 'containerName' => env('OVH_SWIFT_CONTAINER_NAME'), - 'prefix' => env('OVH_SWIFT_PREFIX'), - 'username' => env('OVH_SWIFT_OPENSTACK_USERNAME'), - 'password' => env('OVH_SWIFT_OPENSTACK_PASSWORD'), - 'visibility' => env('OVH_SWIFT_VISIBILITY'), - 'publicUrl' => env('OVH_SWIFT_PUBLIC_URL'), - ]; - - return array_merge($baseConfig, $config); - } - - protected function randomFileName(): string - { - return Str::random() . '.txt'; - } - - protected function randomContent(): string - { - return Str::random(); - } -} diff --git a/tests/PrivateContainerTest.php b/tests/PrivateContainerTest.php new file mode 100644 index 0000000..a8d10af --- /dev/null +++ b/tests/PrivateContainerTest.php @@ -0,0 +1,101 @@ +app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'visibility' => 'private', + 'containerName' => 'test-private', + ])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + $temporaryUrl = Storage::temporaryUrl($fileName, Carbon::now()->addMinute()); + + $this->assertSame($content, file_get_contents($temporaryUrl)); + } + + public function testItSetAPrefix(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'visibility' => 'private', + 'containerName' => 'test-private', + 'prefix' => 'foo', + ])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + $temporaryUrl = Storage::temporaryUrl($fileName, Carbon::now()->addMinute()); + + $this->assertStringEndsWith("foo/{$fileName}", Str::before($temporaryUrl, '?')); + } + + public function testItDoesntUsePrefixIfPrefixIsNull(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'visibility' => 'private', + 'containerName' => 'test-private', + 'prefix' => null, + ])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + $temporaryUrl = Storage::temporaryUrl($fileName, Carbon::now()->addMinute()); + + $this->assertStringEndsWith( + "test-private/{$fileName}", + Str::before($temporaryUrl, '?') + ); + } + + public function testItThrowsWhenUsingUrlOnPrivateContainer(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'visibility' => 'private', + 'containerName' => 'test-private', + ])); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('This driver does not support retrieving URLs because the visibility is not public. Please use temporary URLs.'); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + Storage::url($fileName); + } + + public function testItThrowsWhenNoTempUrlKeyHasBeenSet(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'visibility' => 'private', + 'containerName' => 'test-private', + 'urlKey' => null + ])); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('This driver does not support creating temporary URLs because no temp url key has been configured.'); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + Storage::temporaryUrl($fileName, Carbon::now()->addMinute()); + } +} diff --git a/tests/PublicContainerTest.php b/tests/PublicContainerTest.php new file mode 100644 index 0000000..a64f891 --- /dev/null +++ b/tests/PublicContainerTest.php @@ -0,0 +1,96 @@ +randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + $this->assertSame($content, file_get_contents(Storage::url($fileName))); + } + + public function testItSetAPrefix(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration(['prefix' => 'foo'])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + $this->assertStringEndsWith("foo/{$fileName}", Storage::url($fileName)); + } + + public function testItDoesntUsePrefixIfPrefixIsNull(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration(['prefix' => null])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + $this->assertStringEndsWith( + "{$this->getOvhSwiftConfiguration()['containerName']}/{$fileName}", + Storage::url($fileName) + ); + } + + public function testItUseACustomPublicUrl(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'publicUrl' => 'http://foo.example.com', + 'prefix' => null + ])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + $this->assertSame( + "http://foo.example.com/{$fileName}", + Storage::url($fileName) + ); + } + + public function testItPreservesPrefixWithACustomPublicUrl(): void + { + $this->app['config']->set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration([ + 'publicUrl' => 'http://foo.example.com', + 'prefix' => 'a-prefix' + ])); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + $this->assertSame( + "http://foo.example.com/a-prefix/{$fileName}", + Storage::url($fileName) + ); + } + + public function testItThrowsWhenUsingTemporaryUrlOnPublicContainer(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('This driver does not support creating temporary URLs because the visibility is not private. Please use regular URLs.'); + + $fileName = $this->randomFileName(); + $content = $this->randomContent(); + + Storage::put($fileName, $content); + + Storage::temporaryUrl($fileName, Carbon::now()->addMinute()); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..b13769e --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,63 @@ +set('filesystems.disks.ovh-swift', $this->getOvhSwiftConfiguration()); + $app['config']->set('filesystems.default', 'ovh-swift'); + } + + protected function getOvhSwiftConfiguration(array $config = []): array + { + $baseConfig = [ + 'driver' => 'ovh-swift', + 'authUrl' => env('OVH_SWIFT_OPENSTACK_AUTH_URL'), + 'region' => env('OVH_SWIFT_OPENSTACK_REGION'), + 'projectId' => env('OVH_SWIFT_OPENSTACK_PROJECT_ID'), + 'containerName' => env('OVH_SWIFT_CONTAINER_NAME'), + 'prefix' => env('OVH_SWIFT_PREFIX'), + 'username' => env('OVH_SWIFT_OPENSTACK_USERNAME'), + 'password' => env('OVH_SWIFT_OPENSTACK_PASSWORD'), + 'visibility' => env('OVH_SWIFT_VISIBILITY', 'public'), + 'publicUrl' => env('OVH_SWIFT_PUBLIC_URL'), + 'urlKey' => env('OVH_SWIFT_URL_KEY'), + ]; + + return array_merge($baseConfig, $config); + } + + protected function randomFileName(): string + { + return Str::random() . '.txt'; + } + + protected function randomContent(): string + { + return Str::random(); + } +}