start of rewrite
- update CMake files - add QA and formatting configs
This commit is contained in:
parent
41abb50563
commit
7316fe90e3
119
.clang-format
Normal file
119
.clang-format
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# -*- mode: yaml -*-
|
||||||
|
# Written for clang-format 13.
|
||||||
|
# https://releases.llvm.org/13.0.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||||
|
---
|
||||||
|
DisableFormat: false
|
||||||
|
Language: Cpp
|
||||||
|
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
|
AlignConsecutiveBitFields: None
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignConsecutiveMacros: None
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: Inline
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
# AttributeMacros: ['__capability', '__output', '__ununsed']
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
# BraceWrapping: # If BreakBeforeBraces is set to Custom.
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeConceptDeclarations: true
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
# CommentPragmas:
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
FixNamespaceComments: true
|
||||||
|
# ForEachMacros: ['FOREACH', 'RANGES_FOR', 'Q_FOREACH', 'BOOST_FOREACH' ]
|
||||||
|
# IfMacros: ['IF']
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IncludeCategories: # stdlib headers into own group.
|
||||||
|
- Regex: '^[^\.]+$'
|
||||||
|
Priority: 4
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentExternBlock: NoIndent
|
||||||
|
IndentGotoLabels: false
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentRequires: true # Not sure yet
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
# MacroBlockBegin:
|
||||||
|
# MacroBlockEnd:
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
# NamespaceMacros:
|
||||||
|
PenaltyBreakAssignment: 250
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 300
|
||||||
|
# PenaltyBreakComment: 300
|
||||||
|
# PenaltyBreakFirstLessLess: 120
|
||||||
|
# PenaltyBreakString: 1000
|
||||||
|
# PenaltyBreakTemplateDeclaration: 10
|
||||||
|
# PenaltyExcessCharacter: 1000000
|
||||||
|
# PenaltyIndentedWhitespace:
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 100
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: CaseInsensitive
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementAttributeLikeMacros: [emit]
|
||||||
|
# StatementMacros: [Q_UNUSED, QT_REQUIRE_VERSION]
|
||||||
|
TabWidth: 4
|
||||||
|
# TypenameMacros: ['STACK_OF', 'LIST']
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
# WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE']
|
||||||
|
...
|
51
.clang-tidy
Normal file
51
.clang-tidy
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# -*- mode: conf; fill-column: 100; -*-
|
||||||
|
# Written for clang-tidy 13.
|
||||||
|
|
||||||
|
---
|
||||||
|
Checks: '*,
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-fuchsia-default-arguments-calls,
|
||||||
|
-fuchsia-default-arguments-declarations,
|
||||||
|
-fuchsia-default-arguments,
|
||||||
|
-llvm-include-order,
|
||||||
|
-llvm-header-guard,
|
||||||
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
-fuchsia-overloaded-operator,
|
||||||
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
-readability-magic-numbers,
|
||||||
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
|
-hicpp-no-array-decay,
|
||||||
|
-modernize-avoid-c-arrays,
|
||||||
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
|
-hicpp-avoid-c-arrays,
|
||||||
|
-google-build-using-namespace,
|
||||||
|
-readability-named-parameter,
|
||||||
|
-google-runtime-references,
|
||||||
|
-hicpp-avoid-goto,
|
||||||
|
-hicpp-vararg,
|
||||||
|
-fuchsia-statically-constructed-objects,
|
||||||
|
-google-readability-todo,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
-fuchsia-multiple-inheritance,
|
||||||
|
-llvmlibc*,
|
||||||
|
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||||
|
-cert-*-c,
|
||||||
|
-abseil-string-find-*,
|
||||||
|
-altera-unroll-loops,
|
||||||
|
-altera-id-dependent-backward-branch,
|
||||||
|
-altera-struct-pack-align'
|
||||||
|
FormatStyle: file # Use .clang-format.
|
||||||
|
CheckOptions: # ↓ Clashes with static private member prefix. (static int _var;) ↓
|
||||||
|
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.MemberCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.PrivateMemberPrefix, value: _ }
|
||||||
|
- { key: readability-identifier-naming.ProtectedMemberCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.ProtectedMemberPrefix, value: _ }
|
||||||
|
|
||||||
|
- { key: readability-identifier-naming.ClassCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.StructCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.EnumCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
||||||
|
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
|
||||||
|
...
|
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Configuration file for EditorConfig.
|
||||||
|
# More information is available under <https://editorconfig.org/>.
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 80
|
||||||
|
|
||||||
|
[*.?pp]
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
[{CMakeLists.txt,*.cmake}]
|
||||||
|
indent_size = 2
|
||||||
|
tab_width = 2
|
@ -1,16 +1,20 @@
|
|||||||
cmake_minimum_required(VERSION 3.10...3.20)
|
cmake_minimum_required(VERSION 3.12...3.20)
|
||||||
|
|
||||||
|
# Global build options.
|
||||||
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build.")
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
project(libravatarserv
|
project(libravatarserv
|
||||||
VERSION 0.7.5
|
VERSION 0.8.0
|
||||||
DESCRIPTION "A simple libravatar server."
|
DESCRIPTION "A simple libravatar server."
|
||||||
|
HOMEPAGE_URL "https://schlomp.space/tastytea/libravatarserv"
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(cmake/debug_flags.cmake)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
|
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
|
||||||
@ -19,30 +23,9 @@ if(NOT libcryptopp_FOUND)
|
|||||||
# Debian stretch package installs libcrypto++.pc
|
# Debian stretch package installs libcrypto++.pc
|
||||||
pkg_check_modules(libcryptopp REQUIRED IMPORTED_TARGET libcrypto++)
|
pkg_check_modules(libcryptopp REQUIRED IMPORTED_TARGET libcrypto++)
|
||||||
endif()
|
endif()
|
||||||
pkg_check_modules(libxdg-basedir REQUIRED IMPORTED_TARGET libxdg-basedir)
|
|
||||||
find_package(identiconpp REQUIRED CONFIG)
|
find_package(identiconpp REQUIRED CONFIG)
|
||||||
find_package(Filesystem REQUIRED COMPONENTS Final Experimental)
|
find_package(Filesystem REQUIRED COMPONENTS Final Experimental)
|
||||||
|
|
||||||
include(cmake/debug_flags.cmake)
|
add_subdirectory(src)
|
||||||
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
# Write version in header
|
|
||||||
configure_file(
|
|
||||||
"src/version.hpp.in"
|
|
||||||
"version.hpp")
|
|
||||||
|
|
||||||
# Include <filesystem> or <experimental/filesystem>.
|
|
||||||
configure_file("src/fs-compat.hpp.in" "fs-compat.hpp" @ONLY)
|
|
||||||
|
|
||||||
file(GLOB sources src/*.cpp)
|
|
||||||
add_executable(${PROJECT_NAME} ${sources})
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
|
||||||
PRIVATE ${PROJECT_BINARY_DIR})
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
|
||||||
PRIVATE PkgConfig::Magick++ PkgConfig::libcryptopp PkgConfig::libxdg-basedir
|
|
||||||
std::filesystem identiconpp::identiconpp)
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
|
||||||
|
|
||||||
include(cmake/packages.cmake)
|
include(cmake/packages.cmake)
|
||||||
|
37
CMakePresets.json
Normal file
37
CMakePresets.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 20,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "common",
|
||||||
|
"hidden": true,
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"binaryDir": "build",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dev",
|
||||||
|
"displayName": "Developer config",
|
||||||
|
"description": "Build with debug symbols",
|
||||||
|
"inherits": "common",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"displayName": "Release config",
|
||||||
|
"description": "Build without debug symbols or tests",
|
||||||
|
"inherits": "common",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -24,9 +24,13 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
|||||||
"-Wdouble-promotion"
|
"-Wdouble-promotion"
|
||||||
"-Wformat=2"
|
"-Wformat=2"
|
||||||
"-ftrapv"
|
"-ftrapv"
|
||||||
"-fsanitize=undefined"
|
|
||||||
"-Og"
|
"-Og"
|
||||||
"-fno-omit-frame-pointer")
|
"-fno-omit-frame-pointer")
|
||||||
|
if(WITH_SANITIZERS)
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-fsanitize=undefined"
|
||||||
|
"-fsanitize=address")
|
||||||
|
endif()
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
list(APPEND tmp_CXXFLAGS
|
list(APPEND tmp_CXXFLAGS
|
||||||
"-Wlogical-op"
|
"-Wlogical-op"
|
||||||
@ -44,8 +48,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
|||||||
endif()
|
endif()
|
||||||
add_compile_options("$<$<CONFIG:Debug>:${tmp_CXXFLAGS}>")
|
add_compile_options("$<$<CONFIG:Debug>:${tmp_CXXFLAGS}>")
|
||||||
|
|
||||||
|
if(WITH_SANITIZERS)
|
||||||
list(APPEND tmp_LDFLAGS
|
list(APPEND tmp_LDFLAGS
|
||||||
"-fsanitize=undefined")
|
"-fsanitize=undefined"
|
||||||
|
"-fsanitize=address")
|
||||||
|
endif()
|
||||||
# add_link_options was introduced in version 3.13.
|
# add_link_options was introduced in version 3.13.
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.13)
|
if(${CMAKE_VERSION} VERSION_LESS 3.13)
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${tmp_LDFLAGS}")
|
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${tmp_LDFLAGS}")
|
||||||
|
@ -1,44 +1,57 @@
|
|||||||
# Packages
|
include(GNUInstallDirs)
|
||||||
set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME})
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR ${${CMAKE_PROJECT_NAME}_VERSION_MAJOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${${CMAKE_PROJECT_NAME}_VERSION_MINOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${${CMAKE_PROJECT_NAME}_VERSION_PATCH})
|
|
||||||
set(CPACK_PACKAGE_VERSION ${${CMAKE_PROJECT_NAME}_VERSION})
|
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Simple libravatar server.")
|
|
||||||
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
|
|
||||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
|
||||||
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
|
|
||||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git"
|
|
||||||
"/.gitignore"
|
|
||||||
"/build/"
|
|
||||||
"\\\\.sublime-"
|
|
||||||
"/.drone.yml")
|
|
||||||
execute_process(COMMAND uname -m
|
|
||||||
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
set(CPACK_PACKAGE_FILE_NAME
|
|
||||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
|
|
||||||
set(CPACK_GENERATOR "TGZ")
|
|
||||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
|
||||||
|
|
||||||
if (WITH_DEB)
|
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
set(CPACK_GENERATOR "DEB")
|
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
|
||||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
# Should be set automatically, but they are not.
|
||||||
execute_process(COMMAND dpkg --print-architecture
|
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
|
||||||
|
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${CMAKE_PROJECT_DESCRIPTION}")
|
||||||
|
|
||||||
|
# DEB
|
||||||
|
# Figure out dependencies automatically.
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||||
|
|
||||||
|
# Should be set automatically, but it is not.
|
||||||
|
execute_process(COMMAND dpkg --print-architecture
|
||||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
set(CPACK_PACKAGE_FILE_NAME
|
|
||||||
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
execute_process(COMMAND lsb_release --codename --short
|
||||||
|
OUTPUT_VARIABLE DEBIAN_CODENAME
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if ("${DEBIAN_CODENAME}" STREQUAL "n/a")
|
||||||
|
set(DEBIAN_CODENAME "unknown")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WITH_RPM)
|
# The default does not produce valid Debian package names.
|
||||||
set(CPACK_GENERATOR "RPM")
|
set(CPACK_DEBIAN_FILE_NAME
|
||||||
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
|
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}_${DEBIAN_CODENAME}.deb")
|
||||||
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
|
|
||||||
set(CPACK_RPM_PACKAGE_REQUIRES "cryptopp++, libMagick++, libxdg-basedir >= 1.2.0")
|
# RPM
|
||||||
|
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
|
||||||
|
|
||||||
|
# Figure out dependencies automatically.
|
||||||
|
set(CPACK_RPM_PACKAGE_AUTOREQ ON)
|
||||||
|
|
||||||
|
# Should be set automatically, but it is not.
|
||||||
|
execute_process(COMMAND uname -m
|
||||||
|
OUTPUT_VARIABLE CPACK_RPM_PACKAGE_ARCHITECTURE
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME
|
||||||
|
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_RPM_PACKAGE_ARCHITECTURE}")
|
||||||
|
|
||||||
|
execute_process(COMMAND lsb_release --id --short
|
||||||
|
OUTPUT_VARIABLE OS
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
if("${OS}" STREQUAL "openSUSE")
|
||||||
|
execute_process(COMMAND lsb_release --release --short
|
||||||
|
OUTPUT_VARIABLE OS_RELEASE
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
set(CPACK_PACKAGE_FILE_NAME
|
set(CPACK_PACKAGE_FILE_NAME
|
||||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
|
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_RPM_PACKAGE_ARCHITECTURE}.opensuse-${OS_RELEASE}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
20
src/CMakeLists.txt
Normal file
20
src/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
configure_file("version.hpp.in" "version.hpp" @ONLY)
|
||||||
|
configure_file("fs-compat.hpp.in" "fs-compat.hpp" @ONLY)
|
||||||
|
|
||||||
|
file(GLOB sources_src CONFIGURE_DEPENDS *.cpp)
|
||||||
|
file(GLOB headers_src CONFIGURE_DEPENDS *.hpp)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME})
|
||||||
|
target_sources(${PROJECT_NAME} PRIVATE "${sources_src}" "${headers_src}")
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
PkgConfig::Magick++
|
||||||
|
PkgConfig::libcryptopp
|
||||||
|
std::filesystem
|
||||||
|
identiconpp::identiconpp)
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
33
src/config.cpp
Normal file
33
src/config.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* This file is part of libravatarserv.
|
||||||
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
|
#include "fs-compat.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
namespace libravatarserv::config {
|
||||||
|
|
||||||
|
config read() {
|
||||||
|
config cfg;
|
||||||
|
cfg.avatar_dir = read_env("LIBRAVATARSERV_DIR", fs::current_path().c_str());
|
||||||
|
cfg.default_fallback = read_env("LIBRAVATARSERV_DEFAULT_FALLBACK", "404");
|
||||||
|
cfg.redirect = (read_env("LIBRAVATARSERV_REDIRECT") == "1");
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libravatarserv::config
|
36
src/config.hpp
Normal file
36
src/config.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* This file is part of libravatarserv.
|
||||||
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBRAVATARSERV_CONFIG_HPP
|
||||||
|
#define LIBRAVATARSERV_CONFIG_HPP
|
||||||
|
|
||||||
|
#include "fs-compat.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace libravatarserv::config {
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
fs::path avatar_dir;
|
||||||
|
std::string default_fallback;
|
||||||
|
bool redirect;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] config read();
|
||||||
|
|
||||||
|
} // namespace libravatarserv::config
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_CONFIG_HPP
|
103
src/hash.cpp
103
src/hash.cpp
@ -1,103 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018, 2020 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
|
|
||||||
#include <cryptopp/filters.h>
|
|
||||||
#include <cryptopp/hex.h>
|
|
||||||
#include <cryptopp/md5.h>
|
|
||||||
#include <cryptopp/sha.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
using namespace libravatarserv;
|
|
||||||
using namespace libravatarserv::hash;
|
|
||||||
|
|
||||||
const string hash::md5(const string &text)
|
|
||||||
{
|
|
||||||
using namespace CryptoPP;
|
|
||||||
Weak::MD5 hash;
|
|
||||||
string digest;
|
|
||||||
|
|
||||||
StringSource s(
|
|
||||||
text, true,
|
|
||||||
new HashFilter(hash, new HexEncoder(new StringSink(digest))));
|
|
||||||
std::transform(digest.begin(), digest.end(), digest.begin(), ::tolower);
|
|
||||||
return digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string hash::sha256(const string &text)
|
|
||||||
{
|
|
||||||
using namespace CryptoPP;
|
|
||||||
SHA256 hash;
|
|
||||||
string digest;
|
|
||||||
|
|
||||||
StringSource s(
|
|
||||||
text, true,
|
|
||||||
new HashFilter(hash, new HexEncoder(new StringSink(digest))));
|
|
||||||
|
|
||||||
std::transform(digest.begin(), digest.end(), digest.begin(), ::tolower);
|
|
||||||
return digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hash::fill_table()
|
|
||||||
{
|
|
||||||
for (const fs::path &path :
|
|
||||||
fs::recursive_directory_iterator(settings::avatar_dir))
|
|
||||||
{
|
|
||||||
if (fs::is_regular_file(path))
|
|
||||||
{
|
|
||||||
string email = path.filename();
|
|
||||||
std::transform(email.begin(), email.end(), email.begin(),
|
|
||||||
::tolower);
|
|
||||||
table.insert({md5(email), email});
|
|
||||||
table.insert({sha256(email), email});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hash::is_valid(const string &digest)
|
|
||||||
{
|
|
||||||
if (digest.length() != 64 && digest.length() != 32)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (std::any_of(digest.begin(), digest.end(), not_hex))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hash::not_hex(const char &c)
|
|
||||||
{
|
|
||||||
if (c >= 0x61 && c <= 0x66)
|
|
||||||
{ // a-f
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (c >= 0x30 && c <= 0x39)
|
|
||||||
{ // 0-9
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
34
src/helpers.cpp
Normal file
34
src/helpers.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* This file is part of libravatarserv.
|
||||||
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace libravatarserv {
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||||
|
std::string_view read_env(const std::string_view name,
|
||||||
|
const std::string_view default_value) {
|
||||||
|
// NOLINTNEXTLINE(concurrency-mt-unsave)
|
||||||
|
const char *env{std::getenv(name.data())};
|
||||||
|
if (env != nullptr) {
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libravatarserv
|
28
src/helpers.hpp
Normal file
28
src/helpers.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* This file is part of libravatarserv.
|
||||||
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBRAVATARSERV_HELPERS_HPP
|
||||||
|
#define LIBRAVATARSERV_HELPERS_HPP
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
namespace libravatarserv {
|
||||||
|
|
||||||
|
[[nodiscard]] std::string_view read_env(std::string_view name,
|
||||||
|
std::string_view default_value = "");
|
||||||
|
|
||||||
|
} // namespace libravatarserv
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_HELPERS_HPP
|
145
src/http.cpp
145
src/http.cpp
@ -1,145 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018,2019,2020 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using std::cerr;
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
using namespace libravatarserv;
|
|
||||||
using namespace libravatarserv::http;
|
|
||||||
|
|
||||||
const Request http::parse_request(const string &request)
|
|
||||||
{
|
|
||||||
if (request.substr(0, 8) == "/favicon")
|
|
||||||
{
|
|
||||||
cout << "Status: 404 Not Found\n\n";
|
|
||||||
std::exit(1);
|
|
||||||
}
|
|
||||||
if (request.substr(0, 8) != "/avatar/"
|
|
||||||
|| request.find("..", 8) != std::string::npos)
|
|
||||||
{
|
|
||||||
cout << "Status: 400 Bad Request\n\n";
|
|
||||||
cerr << "Error: Invalid URL.\n";
|
|
||||||
std::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t size = 80;
|
|
||||||
string fallback;
|
|
||||||
string digest = request.substr(8);
|
|
||||||
std::transform(digest.begin(), digest.end(), digest.begin(), ::tolower);
|
|
||||||
std::size_t pos_digest = digest.find('?');
|
|
||||||
|
|
||||||
if (pos_digest != std::string::npos)
|
|
||||||
{
|
|
||||||
string answer;
|
|
||||||
{
|
|
||||||
answer = get_parameter(request, "s");
|
|
||||||
if (!answer.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
size = static_cast<int16_t>(std::stoul(answer));
|
|
||||||
}
|
|
||||||
catch (const std::exception &)
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
answer = get_parameter(request, "size");
|
|
||||||
if (!answer.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
size = static_cast<int16_t>(std::stoul(answer));
|
|
||||||
}
|
|
||||||
catch (const std::exception &)
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (size > 512)
|
|
||||||
{
|
|
||||||
size = 512;
|
|
||||||
}
|
|
||||||
else if (size <= 0)
|
|
||||||
{
|
|
||||||
size = 80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
answer = get_parameter(request, "d");
|
|
||||||
if (!answer.empty())
|
|
||||||
{
|
|
||||||
fallback = answer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
answer = get_parameter(request, "default");
|
|
||||||
if (!answer.empty())
|
|
||||||
{
|
|
||||||
fallback = answer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
digest = digest.substr(0, pos_digest);
|
|
||||||
pos_digest = digest.find('.');
|
|
||||||
if (pos_digest != std::string::npos)
|
|
||||||
{
|
|
||||||
digest = digest.substr(0, pos_digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {digest, static_cast<uint16_t>(size), fallback};
|
|
||||||
}
|
|
||||||
|
|
||||||
const string http::get_parameter(const string &request, const string ¶meter)
|
|
||||||
{
|
|
||||||
std::size_t pos = request.find("&" + parameter + "=");
|
|
||||||
if (pos == std::string::npos)
|
|
||||||
{
|
|
||||||
pos = request.find("?" + parameter + "=");
|
|
||||||
}
|
|
||||||
if (pos != std::string::npos)
|
|
||||||
{
|
|
||||||
pos += (2 + parameter.length());
|
|
||||||
return request.substr(pos, request.find('&', pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void http::send_redirect(const Request &request)
|
|
||||||
{
|
|
||||||
const char *env = std::getenv("HTTPS");
|
|
||||||
string baseurl;
|
|
||||||
if (env != nullptr && env[1] == 'n')
|
|
||||||
{ // "on"
|
|
||||||
baseurl = "https://seccdn.libravatar.org";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
baseurl = "http://cdn.libravatar.org";
|
|
||||||
}
|
|
||||||
cout << "Status: 307 Temporary Redirect\n";
|
|
||||||
cout << "Location: " << baseurl << "/avatar/" << request.digest
|
|
||||||
<< "?s=" << request.size << "&d=" << request.fallback << endl
|
|
||||||
<< endl;
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018, 2020 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
#include <Magick++/Color.h>
|
|
||||||
#include <Magick++/Exception.h>
|
|
||||||
#include <Magick++/Geometry.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using std::cerr;
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
using namespace libravatarserv;
|
|
||||||
using namespace libravatarserv::image;
|
|
||||||
|
|
||||||
const Image image::get(const string &digest, const uint16_t size)
|
|
||||||
{
|
|
||||||
uint8_t error = 0;
|
|
||||||
Magick::Image img;
|
|
||||||
fs::path filename;
|
|
||||||
|
|
||||||
const auto &entry = hash::table.find(digest);
|
|
||||||
if (entry == hash::table.end())
|
|
||||||
{
|
|
||||||
filename = settings::avatar_dir / "default";
|
|
||||||
if (!fs::is_regular_file(filename))
|
|
||||||
{
|
|
||||||
cerr << "Warning: User not found and no default image set.\n";
|
|
||||||
return {2, img};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filename = settings::avatar_dir / entry->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
img.read(filename);
|
|
||||||
img.resize(Magick::Geometry(size, size));
|
|
||||||
}
|
|
||||||
catch (const Magick::Exception &e)
|
|
||||||
{
|
|
||||||
cerr << "Error: " << e.what() << endl;
|
|
||||||
error = 2;
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
cerr << "Error: " << e.what() << endl;
|
|
||||||
error = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {error, img};
|
|
||||||
}
|
|
||||||
|
|
||||||
void image::write(Image &image)
|
|
||||||
{
|
|
||||||
string magick = image.image.magick();
|
|
||||||
std::transform(magick.begin(), magick.end(), magick.begin(), ::tolower);
|
|
||||||
|
|
||||||
Magick::Blob res_buffer;
|
|
||||||
image.image.magick(magick); // force the same format
|
|
||||||
image.image.write(&res_buffer);
|
|
||||||
|
|
||||||
cout << "Content-Type: image/" << magick << endl;
|
|
||||||
cout << "Content-Length: " << res_buffer.length() << endl << endl;
|
|
||||||
cout.write(static_cast<const char *>(res_buffer.data()),
|
|
||||||
res_buffer.length());
|
|
||||||
}
|
|
@ -1,161 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018, 2019, 2020, 2021 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
#include "version.hpp"
|
|
||||||
|
|
||||||
#include <Magick++/Geometry.h>
|
|
||||||
#include <identiconpp.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace libravatarserv;
|
|
||||||
using std::cerr;
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
|
|
||||||
// Global variables
|
|
||||||
std::map<const string, const string> hash::table;
|
|
||||||
fs::path settings::avatar_dir;
|
|
||||||
settings::Settings settings::settings;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
cout << "Server: libravatarserv/" << global::version << endl;
|
|
||||||
|
|
||||||
const char *request = std::getenv("REQUEST_URI");
|
|
||||||
if (request == nullptr)
|
|
||||||
{
|
|
||||||
cout << "Status: 400 Bad Request\n\n";
|
|
||||||
cerr << "Error: ${REQUEST_URI} is empty.\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
http::Request avatar = http::parse_request(request);
|
|
||||||
if (!hash::is_valid(avatar.digest))
|
|
||||||
{
|
|
||||||
cout << "Status: 400 Bad Request\n\n";
|
|
||||||
cerr << "Error: Hash is invalid\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!settings::find_avatar_dir())
|
|
||||||
{
|
|
||||||
cout << "Status: 503 Service Unavailable\n\n";
|
|
||||||
cerr << "Error: No avatars found.\n";
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
hash::fill_table();
|
|
||||||
settings::read_settings();
|
|
||||||
|
|
||||||
image::Image image = image::get(avatar.digest, avatar.size);
|
|
||||||
if (image.error == 0)
|
|
||||||
{
|
|
||||||
image::write(image);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cerr << "Warning " << std::to_string(image.error)
|
|
||||||
<< ": Could not open file.\n";
|
|
||||||
if (settings::settings.redirect_nouser)
|
|
||||||
{
|
|
||||||
http::send_redirect(avatar);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (avatar.fallback.empty())
|
|
||||||
{
|
|
||||||
avatar.fallback = settings::settings.default_fallback;
|
|
||||||
}
|
|
||||||
if (avatar.fallback.substr(0, 3) == "404")
|
|
||||||
{
|
|
||||||
cout << "Status: 404 Not Found\n\n";
|
|
||||||
}
|
|
||||||
else if (avatar.fallback[0] == '/')
|
|
||||||
{
|
|
||||||
cout << "Status: 307 Temporary Redirect\n";
|
|
||||||
cout << "Location: " << avatar.fallback << endl << endl;
|
|
||||||
}
|
|
||||||
else if (avatar.fallback.substr(0, 2) == "mp"
|
|
||||||
|| avatar.fallback.substr(0, 2) == "mm")
|
|
||||||
{
|
|
||||||
// MD5 hash of 'mp'
|
|
||||||
image = image::get("1f2dfa567dcf95833eddf7aec167fec7", avatar.size);
|
|
||||||
if (image.error == 0)
|
|
||||||
{
|
|
||||||
image::write(image);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cerr << "Error: Mystery person not found.\n";
|
|
||||||
// Jump to last else
|
|
||||||
goto not_implemented;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (avatar.fallback.substr(0, 9) == "identicon"
|
|
||||||
|| avatar.fallback.substr(0, 5) == "retro")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto padwidth = static_cast<uint8_t>(avatar.size / 10);
|
|
||||||
if (avatar.size < 60)
|
|
||||||
{
|
|
||||||
padwidth = 0;
|
|
||||||
}
|
|
||||||
else if (padwidth < 10)
|
|
||||||
{
|
|
||||||
padwidth = 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});
|
|
||||||
image.image = identicon.generate(avatar.digest, avatar.size);
|
|
||||||
image.image.magick("PNG");
|
|
||||||
image::write(image);
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
cout << "Status: 500 Internal Server Error\n\n";
|
|
||||||
cerr << "Error: Couldn't generate identicon (" << e.what()
|
|
||||||
<< ").\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
not_implemented:
|
|
||||||
if (settings::settings.redirect_nofallback)
|
|
||||||
{
|
|
||||||
http::send_redirect(avatar);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cout << "Status: 501 Not Implemented\n\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018, 2020 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBRAVATARSERV_HPP
|
|
||||||
#define LIBRAVATARSERV_HPP
|
|
||||||
|
|
||||||
#include "fs-compat.hpp"
|
|
||||||
|
|
||||||
#include <Magick++/Image.h>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace libravatarserv
|
|
||||||
{
|
|
||||||
|
|
||||||
using std::int8_t;
|
|
||||||
using std::string;
|
|
||||||
using std::uint16_t;
|
|
||||||
using std::uint8_t;
|
|
||||||
|
|
||||||
int main();
|
|
||||||
|
|
||||||
namespace settings
|
|
||||||
{ // settings.cpp
|
|
||||||
extern fs::path avatar_dir;
|
|
||||||
extern struct Settings
|
|
||||||
{
|
|
||||||
string default_fallback = "404";
|
|
||||||
bool redirect_nofallback = false;
|
|
||||||
bool redirect_nouser = false;
|
|
||||||
} settings;
|
|
||||||
|
|
||||||
bool find_avatar_dir();
|
|
||||||
void read_settings();
|
|
||||||
} // namespace settings
|
|
||||||
|
|
||||||
namespace http // http.cpp
|
|
||||||
{
|
|
||||||
struct Request
|
|
||||||
{
|
|
||||||
const string digest;
|
|
||||||
const uint16_t size = 0;
|
|
||||||
string fallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Request parse_request(const string &request);
|
|
||||||
const string get_parameter(const string &request, const string ¶meter);
|
|
||||||
void send_redirect(const Request &request);
|
|
||||||
} // namespace http
|
|
||||||
|
|
||||||
namespace hash // hash.cpp
|
|
||||||
{
|
|
||||||
extern std::map<const string, const string> table;
|
|
||||||
|
|
||||||
const string md5(const string &text);
|
|
||||||
const string sha256(const string &text);
|
|
||||||
bool fill_table();
|
|
||||||
bool is_valid(const string &digest);
|
|
||||||
bool not_hex(const char &c);
|
|
||||||
} // namespace hash
|
|
||||||
|
|
||||||
namespace image // image.cpp
|
|
||||||
{
|
|
||||||
struct Image
|
|
||||||
{
|
|
||||||
uint8_t error = 0;
|
|
||||||
Magick::Image image;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Image get(const string &digest, uint16_t size);
|
|
||||||
void write(Image &image);
|
|
||||||
Image identicon(const string &digest);
|
|
||||||
} // namespace image
|
|
||||||
|
|
||||||
} // namespace libravatarserv
|
|
||||||
|
|
||||||
#endif // LIBRAVATARSERV_HPP
|
|
39
src/main.cpp
Normal file
39
src/main.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/* This file is part of libravatarserv.
|
||||||
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main(int /*argc*/, char * /*argv*/[]) {
|
||||||
|
using namespace libravatarserv;
|
||||||
|
|
||||||
|
std::cout << "Server: libravatarserv/" << version << '\n';
|
||||||
|
|
||||||
|
const std::string uri{read_env("REQUEST_URI")};
|
||||||
|
if (uri.empty()) {
|
||||||
|
std::cout << "Status: 400 Bad Request\n\n";
|
||||||
|
std::cerr << "ERROR: REQUEST_URI is empty.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cfg{config::read()};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,84 +0,0 @@
|
|||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018, 2020 tastytea <tastytea@tastytea.de>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
#include <basedir.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
using namespace libravatarserv;
|
|
||||||
using namespace libravatarserv::settings;
|
|
||||||
|
|
||||||
bool settings::find_avatar_dir()
|
|
||||||
{
|
|
||||||
const char *envdir = std::getenv("LIBRAVATARSERV_DIR");
|
|
||||||
if (envdir == nullptr)
|
|
||||||
{
|
|
||||||
// TODO: Remove AVATAR_DIR in 1.0.0
|
|
||||||
// DEPRECATED because it is potentially used by another program
|
|
||||||
envdir = std::getenv("AVATAR_DIR");
|
|
||||||
}
|
|
||||||
if (envdir != nullptr && fs::is_directory(envdir))
|
|
||||||
{
|
|
||||||
avatar_dir = envdir;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xdgHandle xdg;
|
|
||||||
xdgInitHandle(&xdg);
|
|
||||||
auto data_dirs = xdgDataDirectories(&xdg);
|
|
||||||
const uint8_t size = sizeof(data_dirs) / sizeof(*data_dirs);
|
|
||||||
|
|
||||||
for (uint8_t index = 0; index <= size; ++index)
|
|
||||||
{
|
|
||||||
const string searchdir =
|
|
||||||
data_dirs[index] + string("/libravatarserv");
|
|
||||||
if (fs::is_directory(searchdir))
|
|
||||||
{
|
|
||||||
avatar_dir = searchdir;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xdgWipeHandle(&xdg);
|
|
||||||
if (avatar_dir.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void settings::read_settings()
|
|
||||||
{
|
|
||||||
const char *env = std::getenv("LIBRAVATARSERV_DEFAULT_FALLBACK");
|
|
||||||
if (env != nullptr)
|
|
||||||
{
|
|
||||||
settings.default_fallback = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
env = std::getenv("LIBRAVATARSERV_REDIRECT_NOFALLBACK");
|
|
||||||
if (env != nullptr && env[0] == '1')
|
|
||||||
{
|
|
||||||
settings.redirect_nofallback = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
env = std::getenv("LIBRAVATARSERV_REDIRECT_NOUSER");
|
|
||||||
if (env != nullptr && env[0] == '1')
|
|
||||||
{
|
|
||||||
settings.redirect_nouser = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,19 @@
|
|||||||
#ifndef VERSION_HPP
|
/*!
|
||||||
#define VERSION_HPP
|
* @file
|
||||||
|
*
|
||||||
|
* @brief Version variables.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace global
|
#ifndef LIBRAVATARSERV_VERSION_HPP
|
||||||
{
|
#define LIBRAVATARSERV_VERSION_HPP
|
||||||
static constexpr char version[] = "@PROJECT_VERSION@";
|
|
||||||
} // namespace global
|
|
||||||
|
|
||||||
#endif // VERSION_HPP
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace libravatarserv {
|
||||||
|
|
||||||
|
//! The version of the program.
|
||||||
|
inline constexpr std::string_view version{"@PROJECT_VERSION@"};
|
||||||
|
|
||||||
|
} // namespace libravatarserv
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_VERSION_HPP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user