Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
8a91017272 | |||
849762eba6 | |||
58791fce82 | |||
ed9b0bfcfb | |||
89edcb4de7 | |||
a1f2309dc7 | |||
7328f93b6e | |||
528f4480aa | |||
80ccc2c7a1 | |||
d927ef6ca0 | |||
dc5d843c08 | |||
65004ce1f8 | |||
3039d16919 | |||
2b9575c51a | |||
e4b246bc75 | |||
78a7184250 | |||
6aa3b40faa | |||
17205298cd | |||
cb354e666d | |||
cbd86c7000 | |||
03ae11a842 | |||
7316fe90e3 | |||
41abb50563 | |||
3433f88dcc | |||
8341793768 | |||
6549dcf8e6 | |||
e8c1dcdf2b | |||
e70e07c579 | |||
d523342f6a | |||
891d5d3ca3 | |||
846e85aecf | |||
05c6276d43 | |||
5b71abecf2 | |||
83dbd5b6f4 | |||
a0db3380b1 | |||
b8bfbbeccd | |||
ee4451af6b | |||
e7423c92ca | |||
53466aadef | |||
|
a7c89b0e3f | ||
de7e61a2fe | |||
139e5b24be | |||
1a4ebaf024 | |||
79ed6d6432 | |||
3f32e4ff51 | |||
00a29894e9 | |||
97099f0a8a | |||
fba5c64486 | |||
abe643bb6c | |||
1475bdd3fc | |||
021e9cfc1d | |||
ee6a113e1a | |||
19896e78e0 | |||
e43e3681e9 | |||
2491cb47e0 | |||
5b618eaf55 | |||
7e41468176 |
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 }
|
||||||
|
...
|
237
.drone.yml
237
.drone.yml
|
@ -1,209 +1,50 @@
|
||||||
pipeline:
|
# -*- fill-column: 1000 -*-
|
||||||
download:
|
kind: pipeline
|
||||||
image: plugins/download
|
name: build x86_64
|
||||||
pull: true
|
|
||||||
source: https://schlomp.space/attachments/8cd1fb5b-716a-4143-8173-53ffbef623e3
|
|
||||||
destination: identiconpp.deb
|
|
||||||
|
|
||||||
gcc5:
|
volumes:
|
||||||
image: debian:stretch-slim
|
- name: debian-package-cache
|
||||||
pull: true
|
host:
|
||||||
when:
|
path: /var/cache/debian-package-cache
|
||||||
event: [push, pull_request]
|
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
exclude:
|
||||||
|
- tag
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: GCC 8 / clang 7
|
||||||
|
image: debian:buster-slim
|
||||||
|
pull: always
|
||||||
environment:
|
environment:
|
||||||
- LANG=C.utf8
|
CXX: g++-8
|
||||||
- CXX=g++-5
|
CXXFLAGS: -pipe -O2
|
||||||
- CXXFLAGS=-pipe -O2
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
LANG: C.utf8
|
||||||
commands:
|
commands:
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
- rm /etc/apt/apt.conf.d/docker-clean
|
||||||
- apt-get update -q
|
- apt-get update -q
|
||||||
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
|
- apt-get install -qq build-essential clang pkg-config cmake git libcrypto++-dev libmagick++-dev
|
||||||
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
|
- rm -rf build
|
||||||
- apt-get install -qy gnupg
|
- cmake -S . -B build -DLIBRAVATAR_BUNDLED_IDENTICONPP=YES
|
||||||
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
|
- cmake --build build
|
||||||
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
|
- rm -rf build
|
||||||
- apt-get update -q
|
- CXX="clang++" cmake -S . -B build -DLIBRAVATAR_BUNDLED_IDENTICONPP=YES
|
||||||
- apt-get install -qy -t xenial g++-5
|
- cmake --build build
|
||||||
- apt-get install -qy cmake pkg-config
|
- cd build && make install
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
volumes:
|
volumes:
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
- name: debian-package-cache
|
||||||
|
path: /var/cache/apt/archives
|
||||||
|
|
||||||
gcc6:
|
- name: notification
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
environment:
|
|
||||||
- LANG=C.utf8
|
|
||||||
- CXX=g++-6
|
|
||||||
- CXXFLAGS=-pipe -O2
|
|
||||||
commands:
|
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
|
||||||
- apt-get update -q
|
|
||||||
- apt-get install -qy g++-6 cmake pkg-config
|
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- apt-get install -qy dpkg-dev d-shlibs rpm file wget
|
|
||||||
- gpg --no-tty --import /var/autosign_gpg.key
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
- make install DESTDIR=install
|
|
||||||
- make package
|
|
||||||
- cmake -DWITH_DEB=ON ..
|
|
||||||
- make package
|
|
||||||
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
|
|
||||||
- make package
|
|
||||||
- gpg --verbose --detach-sign *.tar.gz
|
|
||||||
- gpg --verbose --detach-sign *.deb
|
|
||||||
- gpg --verbose --detach-sign *.rpm
|
|
||||||
volumes:
|
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
|
||||||
- /home/tastytea/misc/autosign_gpg.key:/var/autosign_gpg.key
|
|
||||||
|
|
||||||
gcc7:
|
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: [push, pull_request]
|
|
||||||
environment:
|
|
||||||
- LANG=C.utf8
|
|
||||||
- CXX=g++-7
|
|
||||||
- CXXFLAGS=-pipe -O2
|
|
||||||
commands:
|
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
|
||||||
- apt-get update -q
|
|
||||||
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
|
|
||||||
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
|
|
||||||
- apt-get install -qy gnupg
|
|
||||||
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
|
|
||||||
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
|
|
||||||
- apt-get update -q
|
|
||||||
- apt-get install -qy -t xenial g++-7
|
|
||||||
- apt-get install -qy cmake pkg-config
|
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
volumes:
|
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
|
||||||
|
|
||||||
gcc8:
|
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: [push, pull_request]
|
|
||||||
environment:
|
|
||||||
- LANG=C.utf8
|
|
||||||
- CXX=g++-8
|
|
||||||
- CXXFLAGS=-pipe -O2
|
|
||||||
commands:
|
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
|
||||||
- apt-get update -q
|
|
||||||
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
|
|
||||||
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
|
|
||||||
- apt-get install -qy gnupg
|
|
||||||
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
|
|
||||||
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
|
|
||||||
- apt-get update -q
|
|
||||||
- apt-get install -qy -t xenial g++-8
|
|
||||||
- apt-get install -qy cmake pkg-config
|
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
volumes:
|
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
|
||||||
|
|
||||||
clang5:
|
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: [push, pull_request]
|
|
||||||
environment:
|
|
||||||
- LANG=C.utf8
|
|
||||||
- CXX=clang++-5.0
|
|
||||||
- CXXFLAGS=-pipe -O2
|
|
||||||
commands:
|
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
|
||||||
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
|
|
||||||
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list
|
|
||||||
- apt-get update -q
|
|
||||||
- apt-get install -qy -t stretch-backports clang-5.0
|
|
||||||
- apt-get install -qy cmake pkg-config
|
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
volumes:
|
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
|
||||||
|
|
||||||
clang6:
|
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: [push, pull_request]
|
|
||||||
environment:
|
|
||||||
- LANG=C.utf8
|
|
||||||
- CXX=clang++-6.0
|
|
||||||
- CXXFLAGS=-pipe -O2
|
|
||||||
commands:
|
|
||||||
- rm /etc/apt/apt.conf.d/docker-clean
|
|
||||||
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
|
|
||||||
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list
|
|
||||||
- apt-get update -q
|
|
||||||
- apt-get install -qy -t stretch-backports clang-6.0
|
|
||||||
- apt-get install -qy cmake pkg-config
|
|
||||||
- apt-get install -qy libcrypto++-dev libmagick++-dev libxdg-basedir-dev
|
|
||||||
- dpkg -i identiconpp.deb
|
|
||||||
- rm -rf build && mkdir -p build && cd build
|
|
||||||
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
|
|
||||||
- make VERBOSE=1
|
|
||||||
volumes:
|
|
||||||
- /var/cache/debian-package-cache:/var/cache/apt/archives
|
|
||||||
|
|
||||||
prepare_release:
|
|
||||||
image: debian:stretch-slim
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: tag
|
|
||||||
commands:
|
|
||||||
- cp -v build/libravatarserv-${DRONE_TAG}_x86_64.tar.gz .
|
|
||||||
- cp -v build/libravatarserv-${DRONE_TAG}_x86_64.tar.gz.sig .
|
|
||||||
- cp -v build/libravatarserv_${DRONE_TAG}-0_amd64.deb .
|
|
||||||
- cp -v build/libravatarserv_${DRONE_TAG}-0_amd64.deb.sig .
|
|
||||||
- cp -v build/libravatarserv-${DRONE_TAG}-0.x86_64.rpm .
|
|
||||||
- cp -v build/libravatarserv-${DRONE_TAG}-0.x86_64.rpm.sig .
|
|
||||||
gitea_release:
|
|
||||||
image: plugins/gitea-release
|
|
||||||
pull: true
|
|
||||||
when:
|
|
||||||
event: tag
|
|
||||||
base_url: https://schlomp.space
|
|
||||||
secrets: [ gitea_token ]
|
|
||||||
title: ${DRONE_TAG}
|
|
||||||
prerelease: true
|
|
||||||
files:
|
|
||||||
- libravatarserv-${DRONE_TAG}_x86_64.tar.gz
|
|
||||||
- libravatarserv-${DRONE_TAG}_x86_64.tar.gz.sig
|
|
||||||
- libravatarserv_${DRONE_TAG}-0_amd64.deb
|
|
||||||
- libravatarserv_${DRONE_TAG}-0_amd64.deb.sig
|
|
||||||
- libravatarserv-${DRONE_TAG}-0.x86_64.rpm
|
|
||||||
- libravatarserv-${DRONE_TAG}-0.x86_64.rpm.sig
|
|
||||||
checksum:
|
|
||||||
- sha512
|
|
||||||
|
|
||||||
notify:
|
|
||||||
image: drillster/drone-email
|
image: drillster/drone-email
|
||||||
pull: true
|
pull: always
|
||||||
host: cryptoparty-celle.de
|
settings:
|
||||||
secrets: [ email_username, email_password ]
|
host: tzend.de
|
||||||
from: drone@tzend.de
|
from: drone@tzend.de
|
||||||
|
username:
|
||||||
|
from_secret: email_username
|
||||||
|
password:
|
||||||
|
from_secret: email_password
|
||||||
when:
|
when:
|
||||||
status: [ changed, failure ]
|
status: [ changed, failure ]
|
||||||
|
|
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
|
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
|
@ -1,49 +1,54 @@
|
||||||
cmake_minimum_required (VERSION 3.2)
|
cmake_minimum_required(VERSION 3.12...3.20)
|
||||||
project(libravatarserv
|
|
||||||
VERSION 0.7.0
|
|
||||||
LANGUAGES CXX
|
|
||||||
)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
# Global build options.
|
||||||
find_package(PkgConfig REQUIRED)
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build.")
|
||||||
pkg_check_modules(MAGICPP REQUIRED Magick++)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
pkg_check_modules(LIBCRYPTOPP libcryptopp)
|
|
||||||
if(NOT LIBCRYPTOPP_FOUND)
|
|
||||||
# Debian stretch package installs libcrypto++.pc
|
|
||||||
pkg_check_modules(LIBCRYPTOPP REQUIRED libcrypto++)
|
|
||||||
endif()
|
|
||||||
pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
string(REPLACE ";" " " MAGICPP_CFLAGS_STRING "${MAGICPP_CFLAGS}")
|
# project build option
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MAGICPP_CFLAGS_STRING}")
|
option(LIBRAVATAR_BUNDLED_IDENTICONPP "use bundled identiconpp" NO)
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG
|
|
||||||
"${CMAKE_CXX_FLAGS_DEBUG} -Wall -pedantic -Wextra -g -Og -fno-omit-frame-pointer")
|
|
||||||
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
project(libravatarserv
|
||||||
include_directories(${MAGICPP_INCLUDE_DIRS})
|
VERSION 0.9.0
|
||||||
include_directories(${LIBCRYPTOPP_INCLUDE_DIRS})
|
DESCRIPTION "A simple libravatar server."
|
||||||
include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS})
|
HOMEPAGE_URL "https://schlomp.space/tastytea/libravatarserv"
|
||||||
|
LANGUAGES CXX)
|
||||||
|
|
||||||
link_directories(${MAGICPP_LIBRARY_DIRS})
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
link_directories(${LIBCRYPTOPP_LIBRARY_DIRS})
|
|
||||||
link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})
|
|
||||||
|
|
||||||
# Write version in header
|
include(cmake/debug_flags.cmake)
|
||||||
configure_file(
|
|
||||||
"${PROJECT_SOURCE_DIR}/src/version.hpp.in"
|
|
||||||
"${PROJECT_BINARY_DIR}/version.hpp"
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB sources src/*.cpp)
|
find_package(PkgConfig REQUIRED)
|
||||||
add_executable(${CMAKE_PROJECT_NAME} "${sources}")
|
pkg_check_modules(Magick++ REQUIRED IMPORTED_TARGET Magick++)
|
||||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
pkg_check_modules(libcryptopp IMPORTED_TARGET libcryptopp)
|
||||||
"${MAGICPP_LDFLAGS} ${LIBCRYPTOPP_LDFLAGS}"
|
if(NOT libcryptopp_FOUND)
|
||||||
"${LIBXDG_BASEDIR_LDFLAGS} -lstdc++fs -lidenticonpp")
|
# Debian stretch package installs libcrypto++.pc
|
||||||
install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
pkg_check_modules(libcryptopp REQUIRED IMPORTED_TARGET libcrypto++)
|
||||||
install(FILES README.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
endif()
|
||||||
|
if (LIBRAVATAR_BUNDLED_IDENTICONPP)
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(identiconpp
|
||||||
|
GIT_REPOSITORY https://schlomp.space/tastytea/identiconpp.git
|
||||||
|
GIT_TAG 0.7.3
|
||||||
|
)
|
||||||
|
if (NOT CMAKE_VERSION VERSION_LESS 3.14)
|
||||||
|
FetchContent_MakeAvailable(identiconpp)
|
||||||
|
else()
|
||||||
|
FetchContent_GetProperties(identiconpp)
|
||||||
|
if(NOT identiconpp_POPULATED)
|
||||||
|
FetchContent_Populate(identiconpp)
|
||||||
|
add_subdirectory(${identiconpp_SOURCE_DIR} ${identiconpp_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
include(packages.CMakeLists.txt)
|
add_library(identiconpp::identiconpp ALIAS identiconpp)
|
||||||
|
else()
|
||||||
|
find_package(identiconpp REQUIRED CONFIG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Filesystem REQUIRED COMPONENTS Final Experimental)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
128
README.md
128
README.md
|
@ -5,6 +5,8 @@ It is intended to be used as a
|
||||||
[Libravatar](https://www.libravatar.org/) is a free service and an open
|
[Libravatar](https://www.libravatar.org/) is a free service and an open
|
||||||
specification for hosting profile images tied to email or OpenID addresses.
|
specification for hosting profile images tied to email or OpenID addresses.
|
||||||
|
|
||||||
|
**The default branch changed from `master` to `main` on 2022-06-11.**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Avatar delivery based on email addresses
|
* Avatar delivery based on email addresses
|
||||||
|
@ -12,7 +14,9 @@ specification for hosting profile images tied to email or OpenID addresses.
|
||||||
* MD5 hashes
|
* MD5 hashes
|
||||||
* SHA256 hashes
|
* SHA256 hashes
|
||||||
* Variable image size (`s` or `size`)
|
* Variable image size (`s` or `size`)
|
||||||
* Default fallbacks (`d` or `default`): 404, URL, mp/mm, identicon
|
* Default fallbacks (`d` or `default`): 404, mp/mm, identicon (=retro), retro
|
||||||
|
* Requesting file type by appending `.jpg`, `.png`, `.gif` or `.webp` to the
|
||||||
|
hash
|
||||||
|
|
||||||
The API is explained in greater detail at the
|
The API is explained in greater detail at the
|
||||||
[Libravar wiki](https://wiki.libravatar.org/api/).
|
[Libravar wiki](https://wiki.libravatar.org/api/).
|
||||||
|
@ -21,29 +25,34 @@ The API is explained in greater detail at the
|
||||||
|
|
||||||
* OpenID
|
* OpenID
|
||||||
* Because it isn't possible to store filenames with '/' in it on most filesystems.
|
* Because it isn't possible to store filenames with '/' in it on most filesystems.
|
||||||
* The default fallbacks monsterid, wavatar and retro
|
* The default fallbacks monsterid, wavatar, robohash and pagan
|
||||||
* Because I don't think anyone uses them?
|
|
||||||
* Patches welcome
|
* Patches welcome
|
||||||
|
* forcedefault
|
||||||
|
* Fallback URLs for to external sites (due to [CWE-601](https://cwe.mitre.org/data/definitions/601.html))
|
||||||
|
* We have a server setting (`LIBRAVATARSERV_REDIRECT`) to redirect to
|
||||||
|
libravatar.org.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Install nginx and
|
Install nginx and
|
||||||
[fcgiwrap](https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/),
|
[fcgiwrap](https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/),
|
||||||
copy the [example config](https://schlomp.space/tastytea/libravatarserv/src/branch/master/doc/nginx-example.conf) to the nginx configuration directory and edit it
|
copy the [example config](https://schlomp.space/tastytea/libravatarserv/src/branch/main/doc/nginx-example.conf)
|
||||||
according to your needs. Other webservers and cgi spawners will also work, of
|
to the nginx configuration directory and edit it according to your needs. Other
|
||||||
course.
|
webservers and cgi spawners will also work, of course.
|
||||||
|
|
||||||
Add the following DNS records to your nameserver:
|
Add the following DNS records to your nameserver:
|
||||||
```PLAIN
|
``` plain
|
||||||
_avatars._tcp.example.com. IN SRV 0 0 80 avatars.example.com
|
_avatars._tcp.example.com. IN SRV 0 0 80 avatars.example.com
|
||||||
_avatars-sec._tcp.example.com. IN SRV 0 0 443 avatars.example.com
|
_avatars-sec._tcp.example.com. IN SRV 0 0 443 avatars.example.com
|
||||||
```
|
```
|
||||||
|
|
||||||
`_avatars._tcp.example.com` is for HTTP, `_avatars-sec._tcp.example.com` is for
|
`_avatars._tcp.example.com` is for HTTP, `_avatars-sec._tcp.example.com` is for
|
||||||
HTTPS.
|
HTTPS.
|
||||||
|
|
||||||
libravatarserv looks in each of `${XDG_DATA_DIRS}` for a directory named
|
libravatarserv looks in the current working directory for images. You can force
|
||||||
`libravatarserv`. You can force a different directory by setting the environment
|
a different directory by setting the environment variable
|
||||||
variable `LIBRAVATARSERV_DIR` (until 0.3.0 `AVATAR_DIR`).
|
`LIBRAVATARSERV_DIR`. Any file format supported by ImageMagick is supported, but
|
||||||
|
it should be PNG, JPEG or GIF for compatibility.
|
||||||
|
|
||||||
The image files are named like your email address, no file extension. The
|
The image files are named like your email address, no file extension. The
|
||||||
default behaviour for unknown users is to return a 404 error. You can change
|
default behaviour for unknown users is to return a 404 error. You can change
|
||||||
|
@ -53,17 +62,18 @@ unknown email addresses, name it `default`. The default image overrides the
|
||||||
specified fallback in the URL and in the environment variable.
|
specified fallback in the URL and in the environment variable.
|
||||||
|
|
||||||
If you want to support "Mystery persons" (mp/mm) as default avatars, place a
|
If you want to support "Mystery persons" (mp/mm) as default avatars, place a
|
||||||
file named `mp` in the avatar dir. You can use the [default libravatar mystery
|
file named `mp` in the avatar dir. You can use the
|
||||||
person](https://seccdn.libravatar.org/mm/512.png)
|
[default libravatar mystery person](https://git.linux-kernel.at/oliver/ivatar/raw/master/ivatar/static/img/mm.png)
|
||||||
([SVG](https://git.linux-kernel.at/oliver/ivatar/raw/master/ivatar/static/img/mm.svg)), for example.
|
([SVG](https://git.linux-kernel.at/oliver/ivatar/raw/master/ivatar/static/img/mm.svg)),
|
||||||
|
for example.
|
||||||
|
|
||||||
Test your setup on https://www.libravatar.org/tools/check/.
|
Test your setup on <https://www.libravatar.org/tools/check/>.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
The avatar directory could look like this:
|
The avatar directory could look like this:
|
||||||
```PLAIN
|
``` plain
|
||||||
/usr/share/libravatarserv
|
/var/db/libravatarserv
|
||||||
├── [ 32K] default
|
├── [ 32K] default
|
||||||
├── [ 759] user@example.com
|
├── [ 759] user@example.com
|
||||||
└── [ 16] user+newsletter@example.com -> user@example.com
|
└── [ 16] user+newsletter@example.com -> user@example.com
|
||||||
|
@ -77,7 +87,7 @@ Configuration is done through environment variables.
|
||||||
|
|
||||||
The directory containing the avatars.
|
The directory containing the avatars.
|
||||||
|
|
||||||
Default: empty
|
Default: current directory
|
||||||
|
|
||||||
**LIBRAVATARSERV_DEFAULT_FALLBACK**
|
**LIBRAVATARSERV_DEFAULT_FALLBACK**
|
||||||
|
|
||||||
|
@ -87,29 +97,18 @@ parameter.
|
||||||
|
|
||||||
Default: 404
|
Default: 404
|
||||||
|
|
||||||
**LIBRAVATARSERV_REDIRECT_NOFALLBACK**
|
**LIBRAVATARSERV_REDIRECT**
|
||||||
|
|
||||||
Set to 1 to redirect to libravatar.org if the user is not found and the
|
|
||||||
requested fallback is not supported.
|
|
||||||
|
|
||||||
Default: 0
|
|
||||||
|
|
||||||
**LIBRAVATARSERV_REDIRECT_NOUSER**
|
|
||||||
|
|
||||||
Set to 1 to redirect to libravatar.org if the user is not found.
|
Set to 1 to redirect to libravatar.org if the user is not found.
|
||||||
|
|
||||||
Default: 0
|
Default: 1
|
||||||
|
|
||||||
### Things to keep in mind
|
### Things to keep in mind
|
||||||
|
|
||||||
libravatarserv resizes images on the fly and does not cache anything. It also
|
libravatarserv resizes images on the fly and potentially calculates hashes for
|
||||||
calculates both MD5 and SHA256 hashes for every user on every request. This
|
every user on every request. This could seriously strain the ressources of your
|
||||||
could seriously strain the ressources of your computer if many users use the
|
computer if many users use the service. Make sure to set up caching if you
|
||||||
service.
|
expect more than occasional traffic.
|
||||||
|
|
||||||
The algorithm for identicon generation has not been thoroughly tested. The
|
|
||||||
generated images are maybe not individual enough. Please open a bug report if
|
|
||||||
that is the case.
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
@ -118,55 +117,35 @@ that is the case.
|
||||||
Gentoo ebuilds are available via my
|
Gentoo ebuilds are available via my
|
||||||
[repository](https://schlomp.space/tastytea/overlay).
|
[repository](https://schlomp.space/tastytea/overlay).
|
||||||
|
|
||||||
### Automatically generated packages
|
|
||||||
|
|
||||||
Binary packages are generated automatically for each
|
|
||||||
[release](https://schlomp.space/tastytea/libravatarserv/releases) in the
|
|
||||||
formats:
|
|
||||||
|
|
||||||
* deb
|
|
||||||
* rpm
|
|
||||||
* tar.gz
|
|
||||||
|
|
||||||
They are generated on Debian Stretch 64 bit and signed with my
|
|
||||||
[automatic signing key](https://tastytea.de/tastytea_autosign.asc).
|
|
||||||
|
|
||||||
Up to and including 0.6.2, the packages were generated on Ubuntu 16.04 64 bit.
|
|
||||||
|
|
||||||
### From source
|
### From source
|
||||||
|
|
||||||
#### Dependencies
|
#### Dependencies
|
||||||
|
|
||||||
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 5/6/7/8,
|
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 8/11,
|
||||||
[clang](https://llvm.org/) 5/6)
|
[clang](https://llvm.org/) 7)
|
||||||
* [cmake](https://cmake.org/) (at least 3.2)
|
* [cmake](https://cmake.org/) (at least 3.12)
|
||||||
* [crypto++](https://cryptopp.com) (tested: 7.0 / 5.6)
|
* [crypto++](https://cryptopp.com) (tested: 8.6 / 5.6)
|
||||||
* [imagemagick](https://www.imagemagick.org/) (tested: 7.0 / 6.7)
|
* [imagemagick](https://www.imagemagick.org/) (tested: 7.1 / 6.7)
|
||||||
* [libxdg-basedir](http://repo.or.cz/w/libxdg-basedir.git) (tested: 1.2)
|
* [identiconpp](https://schlomp.space/tastytea/identiconpp) (at least: 0.7.1)
|
||||||
* [identiconpp](https://schlomp.space/tastytea/identiconpp) (at least: 0.2.0)
|
|
||||||
|
|
||||||
On a Debian system, install the packages: `build-essential cmake libcrypto++-dev
|
On a Debian system, install the packages: `build-essential pkg-config cmake
|
||||||
libmagick++-dev libxdg-basedir-dev` and
|
libcrypto++-dev libmagick++-dev` and
|
||||||
[identiconpp](https://schlomp.space/tastytea/identiconpp).
|
[identiconpp](https://schlomp.space/tastytea/identiconpp) (or use the bundled).
|
||||||
|
|
||||||
#### Compile
|
#### Compile
|
||||||
|
|
||||||
```SH
|
``` shell
|
||||||
mkdir build
|
cmake -S . -B build
|
||||||
cd build
|
cmake --build build
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### cmake options
|
##### cmake options
|
||||||
|
|
||||||
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build
|
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build
|
||||||
* One of:
|
* `-DLIBRAVATAR_BUNDLED_IDENTICONPP=YES` to use the bundled identiconpp
|
||||||
* `-DWITH_DEB=YES` to generate a deb-package
|
|
||||||
* `-DWITH_RPM=YES` to generate an rpm-package
|
|
||||||
|
|
||||||
To generate a binary package, execute `make package`
|
To install, run `sudo cmake --install build`. To create a linux distribution
|
||||||
|
package, run `cpack -G DEB` or `cpack -G RPM`.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -181,15 +160,8 @@ avatars. The tests were done with a 27KiB image, scaled down from 569px to
|
||||||
512px. It took 3,8s / 5-7s to transfer 50 unique avatars (about 3 KiB each) on
|
512px. It took 3,8s / 5-7s to transfer 50 unique avatars (about 3 KiB each) on
|
||||||
one page.
|
one page.
|
||||||
|
|
||||||
|
This test was done on an older version and may not be accurate any more.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
See https://tastytea.de/
|
See https://tastytea.de/
|
||||||
|
|
||||||
## License & Copyright
|
|
||||||
|
|
||||||
```PLAIN
|
|
||||||
Copyright © 2018 tastytea <tastytea@tastytea.de>.
|
|
||||||
License GPLv3: GNU GPL version 3 <https://www.gnu.org/licenses/gpl-3.0.html>.
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY. This is free software,
|
|
||||||
and you are welcome to redistribute it under certain conditions.
|
|
||||||
```
|
|
||||||
|
|
232
cmake/FindFilesystem.cmake
Normal file
232
cmake/FindFilesystem.cmake
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
|
||||||
|
FindFilesystem
|
||||||
|
##############
|
||||||
|
|
||||||
|
This module supports the C++17 standard library's filesystem utilities. Use the
|
||||||
|
:imp-target:`std::filesystem` imported target to
|
||||||
|
|
||||||
|
Options
|
||||||
|
*******
|
||||||
|
|
||||||
|
The ``COMPONENTS`` argument to this module supports the following values:
|
||||||
|
|
||||||
|
.. find-component:: Experimental
|
||||||
|
:name: fs.Experimental
|
||||||
|
|
||||||
|
Allows the module to find the "experimental" Filesystem TS version of the
|
||||||
|
Filesystem library. This is the library that should be used with the
|
||||||
|
``std::experimental::filesystem`` namespace.
|
||||||
|
|
||||||
|
.. find-component:: Final
|
||||||
|
:name: fs.Final
|
||||||
|
|
||||||
|
Finds the final C++17 standard version of the filesystem library.
|
||||||
|
|
||||||
|
If no components are provided, behaves as if the
|
||||||
|
:find-component:`fs.Final` component was specified.
|
||||||
|
|
||||||
|
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
|
||||||
|
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
|
||||||
|
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
|
||||||
|
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
|
||||||
|
|
||||||
|
|
||||||
|
Imported Targets
|
||||||
|
****************
|
||||||
|
|
||||||
|
.. imp-target:: std::filesystem
|
||||||
|
|
||||||
|
The ``std::filesystem`` imported target is defined when any requested
|
||||||
|
version of the C++ filesystem library has been found, whether it is
|
||||||
|
*Experimental* or *Final*.
|
||||||
|
|
||||||
|
If no version of the filesystem library is available, this target will not
|
||||||
|
be defined.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This target has ``cxx_std_17`` as an ``INTERFACE``
|
||||||
|
:ref:`compile language standard feature <req-lang-standards>`. Linking
|
||||||
|
to this target will automatically enable C++17 if no later standard
|
||||||
|
version is already required on the linking target.
|
||||||
|
|
||||||
|
|
||||||
|
.. _fs.variables:
|
||||||
|
|
||||||
|
Variables
|
||||||
|
*********
|
||||||
|
|
||||||
|
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
|
||||||
|
|
||||||
|
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
|
||||||
|
filesystem library was found, otherwise ``FALSE``.
|
||||||
|
|
||||||
|
.. variable:: CXX_FILESYSTEM_HAVE_FS
|
||||||
|
|
||||||
|
Set to ``TRUE`` when a filesystem header was found.
|
||||||
|
|
||||||
|
.. variable:: CXX_FILESYSTEM_HEADER
|
||||||
|
|
||||||
|
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
|
||||||
|
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
|
||||||
|
found.
|
||||||
|
|
||||||
|
.. variable:: CXX_FILESYSTEM_NAMESPACE
|
||||||
|
|
||||||
|
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
|
||||||
|
depending on whether :find-component:`fs.Final` or
|
||||||
|
:find-component:`fs.Experimental` was found.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
********
|
||||||
|
|
||||||
|
Using `find_package(Filesystem)` with no component arguments:
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
|
||||||
|
find_package(Filesystem REQUIRED)
|
||||||
|
|
||||||
|
add_executable(my-program main.cpp)
|
||||||
|
target_link_libraries(my-program PRIVATE std::filesystem)
|
||||||
|
|
||||||
|
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
|
||||||
|
if(TARGET std::filesystem)
|
||||||
|
# This module has already been processed. Don't do it again.
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
include(CMakePushCheckState)
|
||||||
|
include(CheckIncludeFileCXX)
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
|
||||||
|
cmake_push_check_state()
|
||||||
|
|
||||||
|
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
|
||||||
|
|
||||||
|
# All of our tests required C++17 or later
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
# Normalize and check the component list we were given
|
||||||
|
set(want_components ${Filesystem_FIND_COMPONENTS})
|
||||||
|
if(Filesystem_FIND_COMPONENTS STREQUAL "")
|
||||||
|
set(want_components Final)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Warn on any unrecognized components
|
||||||
|
set(extra_components ${want_components})
|
||||||
|
list(REMOVE_ITEM extra_components Final Experimental)
|
||||||
|
foreach(component IN LISTS extra_components)
|
||||||
|
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Detect which of Experimental and Final we should look for
|
||||||
|
set(find_experimental TRUE)
|
||||||
|
set(find_final TRUE)
|
||||||
|
if(NOT "Final" IN_LIST want_components)
|
||||||
|
set(find_final FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "Experimental" IN_LIST want_components)
|
||||||
|
set(find_experimental FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(find_final)
|
||||||
|
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||||
|
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||||
|
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||||
|
# We found the non-experimental header. Don't bother looking for the
|
||||||
|
# experimental one.
|
||||||
|
set(find_experimental FALSE)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(find_experimental)
|
||||||
|
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||||
|
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||||
|
else()
|
||||||
|
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||||
|
set(_have_fs TRUE)
|
||||||
|
set(_fs_header filesystem)
|
||||||
|
set(_fs_namespace std::filesystem)
|
||||||
|
set(_is_experimental FALSE)
|
||||||
|
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
|
||||||
|
set(_have_fs TRUE)
|
||||||
|
set(_fs_header experimental/filesystem)
|
||||||
|
set(_fs_namespace std::experimental::filesystem)
|
||||||
|
set(_is_experimental TRUE)
|
||||||
|
else()
|
||||||
|
set(_have_fs FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
|
||||||
|
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
|
||||||
|
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
|
||||||
|
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
|
||||||
|
|
||||||
|
set(_found FALSE)
|
||||||
|
|
||||||
|
if(CXX_FILESYSTEM_HAVE_FS)
|
||||||
|
# We have some filesystem library available. Do link checks
|
||||||
|
string(CONFIGURE [[
|
||||||
|
#include <@CXX_FILESYSTEM_HEADER@>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
|
||||||
|
return static_cast<int>(cwd.string().size());
|
||||||
|
}
|
||||||
|
]] code @ONLY)
|
||||||
|
|
||||||
|
# Try to compile a simple filesystem program without any linker flags
|
||||||
|
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||||
|
|
||||||
|
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
|
||||||
|
|
||||||
|
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||||
|
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||||
|
# Add the libstdc++ flag
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||||
|
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||||
|
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||||
|
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||||
|
# Try the libc++ flag
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||||
|
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||||
|
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(can_link)
|
||||||
|
add_library(std::filesystem INTERFACE IMPORTED)
|
||||||
|
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||||
|
set(_found TRUE)
|
||||||
|
|
||||||
|
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||||
|
# Nothing to add...
|
||||||
|
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||||
|
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
|
||||||
|
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||||
|
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_pop_check_state()
|
||||||
|
|
||||||
|
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can compile and link a program using std::filesystem" FORCE)
|
||||||
|
|
||||||
|
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||||
|
message(FATAL_ERROR "Cannot Compile simple program using std::filesystem")
|
||||||
|
endif()
|
69
cmake/debug_flags.cmake
Normal file
69
cmake/debug_flags.cmake
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
# Set compiler flags for Debug builds.
|
||||||
|
# Only has an effect on GCC/Clang >= 5.0.
|
||||||
|
|
||||||
|
set(tmp_CXXFLAGS "")
|
||||||
|
set(tmp_LDFLAGS "")
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"
|
||||||
|
AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5")
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-Wall"
|
||||||
|
"-Wextra"
|
||||||
|
"-Wpedantic"
|
||||||
|
"-Wuninitialized"
|
||||||
|
"-Wshadow"
|
||||||
|
"-Wnon-virtual-dtor"
|
||||||
|
"-Wconversion"
|
||||||
|
"-Wsign-conversion"
|
||||||
|
"-Wold-style-cast"
|
||||||
|
"-Wzero-as-null-pointer-constant"
|
||||||
|
"-Wmissing-declarations"
|
||||||
|
"-Wcast-align"
|
||||||
|
"-Wunused"
|
||||||
|
"-Woverloaded-virtual"
|
||||||
|
"-Wdouble-promotion"
|
||||||
|
"-Wformat=2"
|
||||||
|
"-ftrapv"
|
||||||
|
"-Og"
|
||||||
|
"-fno-omit-frame-pointer")
|
||||||
|
if(WITH_SANITIZERS)
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-fsanitize=undefined"
|
||||||
|
"-fsanitize=address")
|
||||||
|
endif()
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-Wlogical-op"
|
||||||
|
"-Wuseless-cast")
|
||||||
|
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6")
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-Wmisleading-indentation"
|
||||||
|
"-Wduplicated-cond"
|
||||||
|
"-Wnull-dereference")
|
||||||
|
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7")
|
||||||
|
list(APPEND tmp_CXXFLAGS
|
||||||
|
"-Wduplicated-branches")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
add_compile_options("$<$<CONFIG:Debug>:${tmp_CXXFLAGS}>")
|
||||||
|
|
||||||
|
if(WITH_SANITIZERS)
|
||||||
|
list(APPEND tmp_LDFLAGS
|
||||||
|
"-fsanitize=undefined"
|
||||||
|
"-fsanitize=address")
|
||||||
|
endif()
|
||||||
|
# add_link_options was introduced in version 3.13.
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS 3.13)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${tmp_LDFLAGS}")
|
||||||
|
else()
|
||||||
|
add_link_options("$<$<CONFIG:Debug>:${tmp_LDFLAGS}>")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS
|
||||||
|
"No additional compiler flags were set, "
|
||||||
|
"because your compiler was not anticipated.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
unset(tmp_CXXFLAGS)
|
||||||
|
unset(tmp_LDFLAGS)
|
57
cmake/packages.cmake
Normal file
57
cmake/packages.cmake
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
|
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
|
||||||
|
|
||||||
|
# Should be set automatically, but they are not.
|
||||||
|
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_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
# The default does not produce valid Debian package names.
|
||||||
|
set(CPACK_DEBIAN_FILE_NAME
|
||||||
|
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}_${DEBIAN_CODENAME}.deb")
|
||||||
|
|
||||||
|
# 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
|
||||||
|
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_RPM_PACKAGE_ARCHITECTURE}.opensuse-${OS_RELEASE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CPack)
|
|
@ -1,47 +1,35 @@
|
||||||
|
# Use 100 MiB cache with a 1 MiB memory zone (enough for ~8,000 keys).
|
||||||
|
# Delete data that has not been accessed for 30 minutes.
|
||||||
|
fastcgi_cache_path /var/cache/nginx/avatar levels=1:2 keys_zone=avatar:1m
|
||||||
|
max_size=100m inactive=30m use_temp_path=off;
|
||||||
|
fastcgi_cache_key "$scheme$request_method$host$request_uri";
|
||||||
|
add_header X-Cache $upstream_cache_status;
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
listen [::]:443 ssl;
|
listen [::]:443 ssl;
|
||||||
server_name avatar.example.com;
|
server_name avatar.example.com;
|
||||||
|
|
||||||
# access_log /var/log/nginx/avatar main;
|
error_log /var/log/nginx/avatar_log warn;
|
||||||
error_log /var/log/nginx/avatar warn;
|
|
||||||
|
|
||||||
ssl_certificate /var/lib/dehydrated/certs/avatar.example.com/fullchain.pem;
|
ssl_certificate /var/lib/dehydrated/certs/avatar.example.com/fullchain.pem;
|
||||||
ssl_certificate_key /var/lib/dehydrated/certs/avatar.example.com/privkey.pem;
|
ssl_certificate_key /var/lib/dehydrated/certs/avatar.example.com/privkey.pem;
|
||||||
|
|
||||||
# 86400 seconds = 1 day
|
expires 6h;
|
||||||
expires 86400;
|
|
||||||
add_header Cache-Control "public, max-age=86400" always;
|
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
include /etc/nginx/fastcgi_params;
|
include /etc/nginx/fastcgi_params;
|
||||||
fastcgi_pass unix:/var/run/cgi-fcgiwrap.socket-1;
|
fastcgi_pass unix:/var/run/cgi-fcgiwrap.socket-1;
|
||||||
fastcgi_param SCRIPT_FILENAME /usr/bin/libravatarserv;
|
fastcgi_param SCRIPT_FILENAME /usr/bin/libravatarserv;
|
||||||
|
|
||||||
|
# fastcgi_param LIBRAVATARSERV_DIR "/var/db/libravatarserv"
|
||||||
# fastcgi_param LIBRAVATARSERV_DEFAULT_FALLBACK 404;
|
# fastcgi_param LIBRAVATARSERV_DEFAULT_FALLBACK 404;
|
||||||
# fastcgi_param LIBRAVATARSERV_REDIRECT_NOFALLBACK 0;
|
# fastcgi_param LIBRAVATARSERV_REDIRECT 1;
|
||||||
# fastcgi_param LIBRAVATARSERV_REDIRECT_NOUSER 0;
|
|
||||||
}
|
fastcgi_cache avatar;
|
||||||
}
|
fastcgi_cache_valid 200 307 400 501 1h; # Cache answers for up to 1 hour
|
||||||
|
# Cache negative replies that may be temporary for 10 minutes
|
||||||
server {
|
fastcgi_cache_valid 404 500 10m;
|
||||||
listen 80;
|
fastcgi_cache_lock on; # Relay only one identical request at a time.
|
||||||
listen [::]:80;
|
|
||||||
server_name avatar.example.com;
|
|
||||||
|
|
||||||
# access_log /var/log/nginx/avatar main;
|
|
||||||
error_log /var/log/nginx/avatar warn;
|
|
||||||
|
|
||||||
expires 86400;
|
|
||||||
add_header Cache-Control "public, max-age=86400" always;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
include /etc/nginx/fastcgi_params;
|
|
||||||
fastcgi_pass unix:/var/run/cgi-fcgiwrap.socket-1;
|
|
||||||
fastcgi_param SCRIPT_FILENAME /usr/bin/libravatarserv;
|
|
||||||
|
|
||||||
# fastcgi_param LIBRAVATARSERV_DEFAULT_FALLBACK 404;
|
|
||||||
# fastcgi_param LIBRAVATARSERV_REDIRECT_NOFALLBACK 0;
|
|
||||||
# fastcgi_param LIBRAVATARSERV_REDIRECT_NOUSER 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
# Packages
|
|
||||||
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_GENERATOR "DEB")
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
|
||||||
execute_process(COMMAND dpkg --print-architecture
|
|
||||||
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
set(CPACK_PACKAGE_FILE_NAME
|
|
||||||
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WITH_RPM)
|
|
||||||
set(CPACK_GENERATOR "RPM")
|
|
||||||
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
|
|
||||||
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${CMAKE_PROJECT_NAME}")
|
|
||||||
set(CPACK_RPM_PACKAGE_REQUIRES "cryptopp++, libMagick++, libxdg-basedir >= 1.2.0")
|
|
||||||
set(CPACK_PACKAGE_FILE_NAME
|
|
||||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
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
|
2
src/fs-compat.hpp.in
Normal file
2
src/fs-compat.hpp.in
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include <@CXX_FILESYSTEM_HEADER@>
|
||||||
|
namespace fs = @CXX_FILESYSTEM_NAMESPACE@;
|
129
src/hash.cpp
129
src/hash.cpp
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libravatarserv.
|
/* This file is part of libravatarserv.
|
||||||
* Copyright © 2018 tastytea <tastytea@tastytea.de>
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,83 +14,74 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "hash.hpp"
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
|
#include <memory>
|
||||||
#include <cryptopp/md5.h>
|
#include <string>
|
||||||
#include <cryptopp/sha.h>
|
#include <string_view>
|
||||||
|
|
||||||
|
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 // necessary for MD5
|
||||||
|
#include <cryptopp/cryptlib.h>
|
||||||
#include <cryptopp/filters.h>
|
#include <cryptopp/filters.h>
|
||||||
#include <cryptopp/hex.h>
|
#include <cryptopp/hex.h>
|
||||||
#include "libravatarserv.hpp"
|
#include <cryptopp/md5.h>
|
||||||
|
#include <cryptopp/sha.h>
|
||||||
|
|
||||||
using namespace hash;
|
namespace libravatarserv::hash {
|
||||||
|
|
||||||
const string hash::md5(const string &text)
|
std::string generate_hash(const algorithm_t algo, const std::string_view text) {
|
||||||
{
|
|
||||||
using namespace CryptoPP;
|
using namespace CryptoPP;
|
||||||
Weak::MD5 hash;
|
|
||||||
string digest;
|
|
||||||
|
|
||||||
StringSource s(text, true,
|
SHA256 sha256;
|
||||||
new HashFilter(hash,
|
Weak::MD5 md5;
|
||||||
new HexEncoder(new StringSink(digest))));
|
HashTransformation *algo_to_use{&sha256}; // HashFilter calls free()?
|
||||||
std::transform(digest.begin(), digest.end(), digest.begin(), ::tolower);
|
if (algo == algorithm_t::MD5) {
|
||||||
return digest;
|
algo_to_use = &md5;
|
||||||
}
|
|
||||||
|
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string hash;
|
||||||
|
StringSource s(text.data(), true,
|
||||||
|
new HashFilter(*algo_to_use,
|
||||||
|
new HexEncoder(new StringSink(hash))));
|
||||||
|
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string find_email(const request_t &req, const fs::path &directory) {
|
||||||
|
bool default_present{false};
|
||||||
|
for (const fs::path &path : fs::recursive_directory_iterator(directory)) {
|
||||||
|
if (fs::is_regular_file(path)) {
|
||||||
|
std::string email = path.filename();
|
||||||
|
std::transform(email.begin(), email.end(), email.begin(),
|
||||||
|
::tolower);
|
||||||
|
if (generate_hash(req.algo, email) == req.hash) {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
if (email == "default") {
|
||||||
|
default_present = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_present ? "default" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid(const std::string_view hash) {
|
||||||
|
auto 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;
|
return true;
|
||||||
|
}};
|
||||||
|
|
||||||
|
return !std::any_of(hash.begin(), hash.end(), not_hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hash::is_valid(const string &digest)
|
} // namespace libravatarserv::hash
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
41
src/hash.hpp
Normal file
41
src/hash.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* 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_HASH_HPP
|
||||||
|
#define LIBRAVATARSERV_HASH_HPP
|
||||||
|
|
||||||
|
#include "fs-compat.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace libravatarserv::hash {
|
||||||
|
|
||||||
|
// generate hash from text
|
||||||
|
[[nodiscard]] std::string generate_hash(algorithm_t algo,
|
||||||
|
std::string_view text);
|
||||||
|
|
||||||
|
// Match hash to email
|
||||||
|
[[nodiscard]] std::string find_email(const request_t &req,
|
||||||
|
const fs::path &directory);
|
||||||
|
|
||||||
|
// return false if invalid characters are found in hash
|
||||||
|
[[nodiscard]] bool is_valid(std::string_view hash);
|
||||||
|
|
||||||
|
} // namespace libravatarserv::hash
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_HASH_HPP
|
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
|
135
src/http.cpp
135
src/http.cpp
|
@ -1,135 +0,0 @@
|
||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018 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 <iostream>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::cerr;
|
|
||||||
using std::endl;
|
|
||||||
using namespace 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, 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 += (1 + 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;
|
|
||||||
}
|
|
132
src/image.cpp
132
src/image.cpp
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libravatarserv.
|
/* This file is part of libravatarserv.
|
||||||
* Copyright © 2018 tastytea <tastytea@tastytea.de>
|
* Copyright © 2022 tastytea <tastytea@tastytea.de>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,66 +14,90 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include "image.hpp"
|
||||||
#include <sstream>
|
|
||||||
#include <array>
|
#include "types.hpp"
|
||||||
#include <algorithm>
|
|
||||||
|
#include <identiconpp.hpp>
|
||||||
|
#include <Magick++/Blob.h>
|
||||||
#include <Magick++/Geometry.h>
|
#include <Magick++/Geometry.h>
|
||||||
#include <Magick++/Color.h>
|
#include <Magick++/Image.h>
|
||||||
#include <Magick++/Exception.h>
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
using std::cout;
|
#include <algorithm>
|
||||||
using std::cerr;
|
#include <cstdint>
|
||||||
using std::endl;
|
#include <ios>
|
||||||
using namespace image;
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
const Image image::get(const string &digest, const uint16_t size)
|
namespace libravatarserv::image {
|
||||||
{
|
|
||||||
uint8_t error = 0;
|
Magick::Image get(const fs::path &filepath, const size_t size) {
|
||||||
Magick::Image img;
|
Magick::Image img;
|
||||||
fs::path filename;
|
img.read(filepath);
|
||||||
|
|
||||||
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));
|
img.resize(Magick::Geometry(size, size));
|
||||||
}
|
return img;
|
||||||
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)
|
Magick::Image generate_identicon(const request_t &req) {
|
||||||
{
|
|
||||||
string magick = image.image.magick();
|
const auto padwidth{[&req]() -> std::uint8_t {
|
||||||
|
if (req.size < 60) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<std::uint8_t>(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<std::uint8_t>(req.size))};
|
||||||
|
img.magick("PNG");
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(Magick::Image &img,
|
||||||
|
const std::optional<std::string_view> magick_force) {
|
||||||
|
std::string magick{magick_force.value_or(img.magick())};
|
||||||
std::transform(magick.begin(), magick.end(), magick.begin(), ::tolower);
|
std::transform(magick.begin(), magick.end(), magick.begin(), ::tolower);
|
||||||
|
|
||||||
cout << "Content-Type: image/" << magick << endl << endl;
|
const auto quality{[&img, &magick]() -> size_t {
|
||||||
cout.flush(); // We need to flush before we use /dev/stdout directly.
|
if (img.quality() != 0) {
|
||||||
image.image.write("/dev/stdout");
|
return img.quality(); // same as source
|
||||||
|
}
|
||||||
|
if (magick == "png") {
|
||||||
|
return 100; // highest compression
|
||||||
|
}
|
||||||
|
if (magick == "webp") {
|
||||||
|
if (img.magick() == "WEBP" || img.magick() == "PNG"
|
||||||
|
|| img.magick() == "GIF" || img.magick() == "SVG") {
|
||||||
|
return 100; // lossless
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; // default
|
||||||
|
}()};
|
||||||
|
|
||||||
|
img.magick(magick);
|
||||||
|
img.quality(quality);
|
||||||
|
|
||||||
|
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<const char *>(buffer.data()),
|
||||||
|
static_cast<std::streamsize>(buffer.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace libravatarserv::image
|
||||||
|
|
41
src/image.hpp
Normal file
41
src/image.hpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* 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_IMAGE_HPP
|
||||||
|
#define LIBRAVATARSERV_IMAGE_HPP
|
||||||
|
|
||||||
|
#include "fs-compat.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
#include <Magick++/Image.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace libravatarserv::image {
|
||||||
|
|
||||||
|
// read image from file
|
||||||
|
[[nodiscard]] Magick::Image get(const fs::path &filepath, size_t size);
|
||||||
|
|
||||||
|
// Generate identicon from hash
|
||||||
|
[[nodiscard]] Magick::Image generate_identicon(const request_t &req);
|
||||||
|
|
||||||
|
// write image with headers to stdout
|
||||||
|
void write(Magick::Image &img,
|
||||||
|
std::optional<std::string_view> magick_force = {});
|
||||||
|
|
||||||
|
} // namespace libravatarserv::image
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_IMAGE_HPP
|
|
@ -1,153 +0,0 @@
|
||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018 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 <iostream>
|
|
||||||
#include <Magick++/Geometry.h>
|
|
||||||
#include <identiconpp.hpp>
|
|
||||||
#include "version.hpp"
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::cerr;
|
|
||||||
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.substr(0, 4) == "http")
|
|
||||||
{
|
|
||||||
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")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Identiconpp identicon(4, 4, Identiconpp::algorithm::sigil,
|
|
||||||
"ffffffff",
|
|
||||||
{ // The 16 named colors specified in HTML 4.01
|
|
||||||
// minus white, silver and gray.
|
|
||||||
"000000ff", // Black
|
|
||||||
"ff0000ff", // Red
|
|
||||||
"800000ff", // Maroon
|
|
||||||
"ffff00ff", // Yellow
|
|
||||||
"808000ff", // Olive
|
|
||||||
"00ff00ff", // lime
|
|
||||||
"008000ff", // Green
|
|
||||||
"00ffffff", // Aqua
|
|
||||||
"008080ff", // Teal
|
|
||||||
"0000ffff", // Blue
|
|
||||||
"000080ff", // Navy
|
|
||||||
"ff00ffff", // Fuchsia
|
|
||||||
"800080ff", // Purple
|
|
||||||
});
|
|
||||||
Magick::Image img;
|
|
||||||
img = identicon.generate(avatar.digest, avatar.size);
|
|
||||||
image::Image image({ 0, img });
|
|
||||||
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,93 +0,0 @@
|
||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018 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
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
#include <filesystem>
|
|
||||||
#else
|
|
||||||
#include <experimental/filesystem>
|
|
||||||
#endif
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <Magick++/Image.h>
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
#else
|
|
||||||
namespace fs = std::experimental::filesystem;
|
|
||||||
#endif
|
|
||||||
using std::string;
|
|
||||||
using std::uint16_t;
|
|
||||||
using std::uint8_t;
|
|
||||||
using std::int8_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 http // http.cpp
|
|
||||||
{
|
|
||||||
struct Request
|
|
||||||
{
|
|
||||||
const string digest;
|
|
||||||
const int16_t size;
|
|
||||||
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 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 image // image.cpp
|
|
||||||
{
|
|
||||||
struct Image
|
|
||||||
{
|
|
||||||
uint8_t error;
|
|
||||||
Magick::Image image;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Image get(const string &digest, const uint16_t size);
|
|
||||||
void write(Image &image);
|
|
||||||
Image identicon(const string &digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // LIBRAVATARSERV_HPP
|
|
108
src/main.cpp
Normal file
108
src/main.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/* 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 "hash.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "request.hpp"
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
|
#include <Magick++/Exception.h>
|
||||||
|
#include <Magick++/Image.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main(int /*argc*/, char * /*argv*/[]) {
|
||||||
|
using namespace libravatarserv;
|
||||||
|
|
||||||
|
std::cout << "Server: libravatarserv/" << version << '\n';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const std::string uri{read_env("REQUEST_URI")};
|
||||||
|
if (uri.empty()) {
|
||||||
|
std::cout << "Status: 400 Bad Request\n\n";
|
||||||
|
throw std::runtime_error{"REQUEST_URI is empty"};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cfg{config::read()};
|
||||||
|
|
||||||
|
auto req{request::parse(uri)};
|
||||||
|
std::string email{hash::find_email(req, cfg.avatar_dir)};
|
||||||
|
|
||||||
|
Magick::Image img;
|
||||||
|
|
||||||
|
if (!email.empty()) {
|
||||||
|
try {
|
||||||
|
img = image::get(cfg.avatar_dir / email,
|
||||||
|
static_cast<size_t>(req.size));
|
||||||
|
} catch (const Magick::Exception &e) {
|
||||||
|
std::cout << "Status: 500 Internal Server Error\n\n";
|
||||||
|
std::cerr << "ERROR: " << e.what() << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} 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, req.magick);
|
||||||
|
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
if (std::strlen(e.what()) != 0) {
|
||||||
|
std::cerr << "ERROR: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
122
src/request.cpp
Normal file
122
src/request.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/* 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 "request.hpp"
|
||||||
|
|
||||||
|
#include "hash.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace libravatarserv::request {
|
||||||
|
|
||||||
|
request_t parse(const std::string_view uri) {
|
||||||
|
constexpr std::uint8_t offset{8};
|
||||||
|
if (uri.substr(0, offset) != "/avatar/"
|
||||||
|
|| uri.find("..", offset) != std::string_view::npos) {
|
||||||
|
std::cout << "Status: 400 Bad Request\n\n";
|
||||||
|
throw std::runtime_error{"Invalid URL"};
|
||||||
|
}
|
||||||
|
|
||||||
|
request_t req;
|
||||||
|
req.size = 80;
|
||||||
|
|
||||||
|
size_t pos{uri.find('?')};
|
||||||
|
if (pos == std::string_view::npos) {
|
||||||
|
pos = uri.size();
|
||||||
|
}
|
||||||
|
req.hash.resize(pos - offset);
|
||||||
|
std::transform(uri.begin() + offset, uri.begin() + pos, req.hash.begin(),
|
||||||
|
::tolower);
|
||||||
|
|
||||||
|
if (const auto pos_dot{req.hash.find('.')}; pos_dot != std::string::npos) {
|
||||||
|
std::string magick{req.hash.substr(pos_dot + 1)};
|
||||||
|
req.hash = req.hash.substr(0, pos_dot);
|
||||||
|
|
||||||
|
if (magick == "jpg") {
|
||||||
|
magick = "jpeg";
|
||||||
|
}
|
||||||
|
constexpr std::array<std::string_view, 4> allowed{
|
||||||
|
{"jpeg", "png", "gif", "webp"}
|
||||||
|
};
|
||||||
|
if (std::any_of(allowed.begin(), allowed.end(),
|
||||||
|
[magick](const std::string_view supplied) {
|
||||||
|
return magick == supplied;
|
||||||
|
})) {
|
||||||
|
req.magick = magick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.hash.size() == 64 && hash::is_valid(req.hash)) {
|
||||||
|
req.algo = algorithm_t::SHA256;
|
||||||
|
} else if (req.hash.size() == 32 && hash::is_valid(req.hash)) {
|
||||||
|
req.algo = algorithm_t::MD5;
|
||||||
|
} else {
|
||||||
|
std::cout << "Status: 400 Bad Request\n\n";
|
||||||
|
throw std::runtime_error{"Invalid hash"};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != uri.size()) {
|
||||||
|
std::string uri_rest;
|
||||||
|
uri_rest.resize(uri.size() - pos);
|
||||||
|
std::transform(uri.begin() + pos, uri.end(), uri_rest.begin(),
|
||||||
|
::tolower);
|
||||||
|
|
||||||
|
auto strsize{get_parameter(uri_rest, "s")};
|
||||||
|
if (strsize.empty()) {
|
||||||
|
strsize = get_parameter(uri_rest, "size");
|
||||||
|
}
|
||||||
|
if (!strsize.empty()) {
|
||||||
|
try {
|
||||||
|
req.size = static_cast<int16_t>(std::stoul(strsize.data()));
|
||||||
|
if (req.size > 512) {
|
||||||
|
req.size = 512;
|
||||||
|
} else if (req.size < 1) {
|
||||||
|
req.size = 80;
|
||||||
|
}
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.fallback = get_parameter(uri_rest, "d");
|
||||||
|
if (req.fallback.empty()) {
|
||||||
|
req.fallback = get_parameter(uri_rest, "default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view get_parameter(const std::string_view uri,
|
||||||
|
const std::string ¶meter) {
|
||||||
|
size_t pos{uri.find("?" + parameter + "=")};
|
||||||
|
if (pos == std::string_view::npos) {
|
||||||
|
pos = uri.find("&" + parameter + "=");
|
||||||
|
}
|
||||||
|
if (pos != std::string_view::npos) {
|
||||||
|
pos += (2 + parameter.length());
|
||||||
|
return uri.substr(pos, uri.find('&', pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libravatarserv::request
|
36
src/request.hpp
Normal file
36
src/request.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_REQUEST_HPP
|
||||||
|
#define LIBRAVATARSERV_REQUEST_HPP
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace libravatarserv::request {
|
||||||
|
|
||||||
|
// parse request and return results
|
||||||
|
[[nodiscard]] request_t parse(std::string_view uri);
|
||||||
|
|
||||||
|
// get one parameter from an URI
|
||||||
|
[[nodiscard]] std::string_view get_parameter(std::string_view uri,
|
||||||
|
const std::string ¶meter);
|
||||||
|
|
||||||
|
} // namespace libravatarserv::request
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_REQUEST_HPP
|
|
@ -1,82 +0,0 @@
|
||||||
/* This file is part of libravatarserv.
|
|
||||||
* Copyright © 2018 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 <cstdlib>
|
|
||||||
#include <basedir.h>
|
|
||||||
#include "libravatarserv.hpp"
|
|
||||||
|
|
||||||
using namespace 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;
|
|
||||||
}
|
|
||||||
}
|
|
40
src/types.hpp
Normal file
40
src/types.hpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* 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_TYPES_HPP
|
||||||
|
#define LIBRAVATARSERV_TYPES_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
namespace libravatarserv {
|
||||||
|
|
||||||
|
enum class algorithm_t {
|
||||||
|
SHA256,
|
||||||
|
MD5
|
||||||
|
};
|
||||||
|
|
||||||
|
struct request_t {
|
||||||
|
std::string hash;
|
||||||
|
algorithm_t algo;
|
||||||
|
std::int16_t size;
|
||||||
|
std::string fallback;
|
||||||
|
std::optional<std::string> magick;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace libravatarserv
|
||||||
|
|
||||||
|
#endif // LIBRAVATARSERV_TYPES_HPP
|
|
@ -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@";
|
|
||||||
}
|
|
||||||
|
|
||||||
#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…
Reference in New Issue
Block a user