cpp-lib/zerostoragecaptcha.h

171 lines
5.4 KiB
C++

// GPLv3 (c) acetone, 2022
// Zero Storage Captcha
// PNG generation based on:
/*
* Copyright (c) 2014 Omkar Kanase
* QtCaptcha: https://github.com/omkar-developer/QtCaptcha
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ZEROSTORAGECAPTCHA_H
#define ZEROSTORAGECAPTCHA_H
#include <QFont>
#include <QImage>
#include <QString>
#include <QTimer>
#include <QMutex>
#include <QSet>
#include <QMap>
class ZeroStorageCaptcha
{
public:
ZeroStorageCaptcha();
ZeroStorageCaptcha(const QString& answer, int difficulty = 1);
static bool validate(const QString& answer, const QString& token);
static void setNumbersOnlyMode(bool enabled = false) { m_onlyNumbers = enabled; }
static bool numbersOnlyMode() { return m_onlyNumbers; }
static void setCaseSensitive(bool enabled = false);
static bool caseSensitive();
QString answer() const { return m_captchaText; }
QString token() const;
QByteArray picturePng() const;
QImage qimage() const { return m_captchaImage; }
QFont font() const { return m_font; }
QColor fontColor() const { return m_fontColor; }
QColor backColor() const { return m_backColor; }
bool drawLines() const { return m_drawLines; }
bool drawEllipses() const { return m_drawLines; }
bool drawNoise() const { return m_drawLines; }
int noiseCount() const { return m_noiseCount; }
int lineCount() const { return m_lineCount; }
int ellipseCount() const { return m_ellipseCount; }
int lineWidth() const { return m_lineWidth; }
int ellipseMinRadius() const { return m_ellipseMinRadius; }
int ellipseMaxRadius() const { return m_ellipseMaxRadius; }
int noisePointSize() const { return m_noisePointSize; }
void setFont(const QFont& arg) { m_font = arg; }
void setCaptchaText(QString arg) { m_captchaText = arg; }
void setFontColor(QColor arg) { m_fontColor = arg; }
void setBackColor(QColor arg) { m_backColor = arg; }
void setDrawLines(bool arg) { m_drawLines = arg; }
void setDrawEllipses(bool arg) { m_drawEllipses = arg; }
void setDrawNoise(bool arg) { m_drawNoise = arg; }
void setNoiseCount(int arg) { m_noiseCount = arg; }
void setLineCount(int arg) { m_lineCount = arg; }
void setEllipseCount(int arg) { m_ellipseCount = arg; }
void setLineWidth(int arg) { m_lineWidth = arg; }
void setEllipseMinRadius(int arg) { m_ellipseMinRadius = arg; }
void setEllipseMaxRadius(int arg) { m_ellipseMaxRadius = arg; }
void setNoisePointSize(int arg) { m_noisePointSize = arg; }
void setSinDeform(qreal hAmplitude, qreal hFrequency, qreal vAmplitude, qreal vFrequency);
void setDifficulty(int val);
void setAnswer(const QString& answer);
void generateAnswer(int length = 5);
void render();
private:
void init();
static bool m_onlyNumbers;
qreal m_hmod1;
qreal m_hmod2;
qreal m_vmod1;
qreal m_vmod2;
QFont m_font;
QImage m_captchaImage;
QString m_captchaText = "empty";
QColor m_fontColor;
QColor m_backColor;
qreal m_padding;
bool m_drawLines;
bool m_drawEllipses;
bool m_drawNoise;
int m_noiseCount;
int m_lineCount;
int m_ellipseCount;
int m_lineWidth;
int m_ellipseMinRadius;
int m_ellipseMaxRadius;
int m_noisePointSize;
mutable QString m_token;
};
///////////////////////////////////
namespace ZeroStorageCaptchaService {
QByteArray random(int length, bool onlyNumbers = false);
class TimeToken
{
public:
TimeToken() = delete;
static void init();
static const QString currentToken() { return m_current; }
static const QString prevToken() { return m_prev; }
private:
static QTimer* m_updater;
static QString m_current;
static QString m_prev;
};
class IdCounter
{
public:
IdCounter() = delete;
static size_t get();
private:
static std::atomic<size_t> m_counter;
};
class TokenManager
{
public:
TokenManager() = delete;
static QString get(const QString& captchaAnswer, size_t id = 0, bool prevTimeToken = false);
static bool validateAnswer(const QString& answer, const QString& token);
static void setCaseSensitive(bool enabled = false) { m_caseSensitive = enabled; }
static bool caseSensitive() { return m_caseSensitive; }
friend TimeToken;
private:
static void removeAllTokensExceptPassed(const QString& current, const QString& prev);
static QMutex m_usedTokensMtx;
static QMap<QString, QSet<size_t>> m_usedTokens;
static bool m_caseSensitive;
static QString m_key;
};
} // namespace
#endif // ZEROSTORAGECAPTCHA_H