From 17205298cd24e978b9bff9c08c4f99e6410df2cb Mon Sep 17 00:00:00 2001 From: tastytea Date: Sat, 11 Jun 2022 04:46:54 +0200 Subject: [PATCH] implement fallbacks --- src/image.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/image.hpp | 33 +++++++++++++++++++++++ src/main.cpp | 54 ++++++++++++++++++++++++++++++++----- 3 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/image.cpp create mode 100644 src/image.hpp diff --git a/src/image.cpp b/src/image.cpp new file mode 100644 index 0000000..e83e050 --- /dev/null +++ b/src/image.cpp @@ -0,0 +1,73 @@ +/* This file is part of libravatarserv. + * Copyright © 2022 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "image.hpp" + +#include "types.hpp" + +#include +#include +#include + +#include +#include +#include +#include + +namespace libravatarserv::image { + +void write(Magick::Image &img) { + string magick{img.magick()}; + std::transform(magick.begin(), magick.end(), magick.begin(), ::tolower); + + Magick::Blob buffer; + img.write(&buffer); + + std::cout << "Content-Type: image/" << magick << '\n'; + std::cout << "Content-Length: " << buffer.length() << "\n\n"; + std::cout.write(static_cast(buffer.data()), + static_cast(buffer.length())); +} + +Magick::Image generate_identicon(const request_t &req) { + + const auto padwidth{[&req]() -> std::uint8_t { + if (req.size < 60) { + return 0; + } + return static_cast(std::max(req.size / 10, 10)); + }()}; + + Identiconpp identicon(5, 5, Identiconpp::algorithm::sigil, "fefefeff", + { + // The same colors ivatar uses. + "2d4fffff", // Blue + "feb42cff", // Yellow + "e279eaff", // Bright pink + "1eb3fdff", // Cyan + "E84D41ff", // Red + "31CB73ff", // Green + "8D45AAff" // Dark pink + }, + {padwidth, padwidth}); + Magick::Image img{ + identicon.generate(req.hash, static_cast(req.size))}; + img.magick("PNG"); + + return img; +} + +} // namespace libravatarserv::image diff --git a/src/image.hpp b/src/image.hpp new file mode 100644 index 0000000..cc89b9e --- /dev/null +++ b/src/image.hpp @@ -0,0 +1,33 @@ +/* This file is part of libravatarserv. + * Copyright © 2022 tastytea + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBRAVATARSERV_IMAGE_HPP +#define LIBRAVATARSERV_IMAGE_HPP + +#include "types.hpp" + +#include + +namespace libravatarserv::image { + +void write(Magick::Image &img); + +// Generate identicon from hash +[[nodiscard]] Magick::Image generate_identicon(const request_t &req); + +} // namespace libravatarserv::image + +#endif // LIBRAVATARSERV_IMAGE_HPP diff --git a/src/main.cpp b/src/main.cpp index 7b583e2..ea8730e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,11 +15,15 @@ */ #include "config.hpp" +#include "fs-compat.hpp" #include "hash.hpp" #include "helpers.hpp" +#include "image.hpp" #include "request.hpp" #include "version.hpp" +#include + #include #include #include @@ -40,14 +44,50 @@ int main(int /*argc*/, char * /*argv*/[]) { auto cfg{config::read()}; auto req{request::parse(uri)}; - if (req.fallback.empty()) { - req.fallback = cfg.default_fallback; - } - const std::string email{hash::find_email(req, cfg.avatar_dir)}; + std::string email{hash::find_email(req, cfg.avatar_dir)}; - std::cout << " HASH: " << req.hash << "\n SIZE: " << req.size - << "\n FALLBACK: " << req.fallback << "\n EMAIL: " << email - << '\n'; + Magick::Image img; + + if (!email.empty()) { + // img = image::get(cfg.avatar_dir / email, req.size); + } else { + if (cfg.redirect) { + std::cout << "Status: 307 Temporary Redirect\n"; + std::cout << "Location: https://seccdn.libravatar.org/avatar/" + << req.hash << "?s=" << req.size + << "&d=" << req.fallback << "\n\n"; + return 0; + } + if (req.fallback.empty()) { + req.fallback = cfg.default_fallback; + } + if (req.fallback == "404") { + std::cout << "Status: 404 Not Found\n\n"; + return 0; + } + + if (req.fallback == "mp" || req.fallback == "mm") { + if (!fs::exists(cfg.avatar_dir / "mp")) { + std::cout << "Status: 404 Not Found\n\n"; + return 0; + } + email = "mp"; + } else if (req.fallback == "identicon" || req.fallback == "retro") { + try { + img = image::generate_identicon(req); + } catch (const std::exception &e) { + std::cout << "Status: 500 Internal Server Error\n\n"; + std::cerr + << "ERROR: could not generate identicon: " << e.what() + << "\n"; + return 1; + } + } else { + std::cout << "Status: 501 Not Implemented\n\n"; + } + } + + image::write(img); } catch (const std::runtime_error &e) { if (std::strlen(e.what()) != 0) {