Line data Source code
1 : /**
2 : Copyright (c) 2018-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPDbAuth.h"
25 : #include "SPDbScheme.h"
26 : #include "SPValid.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::db {
29 :
30 575 : Auth::Auth(const ApplicationInterface *app, const Scheme &s) : _application(app), _scheme(&s) {
31 575 : if (auto f = detectPasswordField(*_scheme)) {
32 575 : _password = f;
33 : }
34 575 : }
35 0 : Auth::Auth(const ApplicationInterface *app, const Scheme &s, const StringView &name, const StringView &password) : _application(app), _scheme(&s) {
36 0 : if (!name.empty()) {
37 0 : if (auto f = s.getField(name)) {
38 0 : _name = f;
39 : }
40 : }
41 :
42 0 : if (!password.empty()) {
43 0 : if (auto f = s.getField(password)) {
44 0 : _password = f;
45 : }
46 : }
47 :
48 0 : if (!_password) {
49 0 : if (auto f = detectPasswordField(*_scheme)) {
50 0 : _password = f;
51 : }
52 : }
53 0 : }
54 0 : Auth::Auth(const ApplicationInterface *app, const Scheme &s, const Field *name, const Field *password) : _application(app), _scheme(&s) {
55 0 : _name = name;
56 0 : _password = password;
57 0 : }
58 :
59 0 : Auth::Auth(const ApplicationInterface *app, const Scheme &s, const NameFieldCallback &cb, const Field *password) : _application(app), _scheme(&s) {
60 0 : _nameFieldCallback = cb;
61 0 : _password = password;
62 0 : }
63 0 : Auth::Auth(const ApplicationInterface *app, const Scheme &s, const NameFieldCallback &cb, const StringView &password) : _application(app), _scheme(&s) {
64 0 : _nameFieldCallback = cb;
65 0 : if (!password.empty()) {
66 0 : if (auto f = s.getField(password)) {
67 0 : _password = f;
68 : }
69 : }
70 0 : if (!_password) {
71 0 : if (auto f = detectPasswordField(*_scheme)) {
72 0 : _password = f;
73 : }
74 : }
75 0 : }
76 :
77 2250 : const Scheme &Auth::getScheme() const {
78 2250 : return *_scheme;
79 : }
80 :
81 575 : stappler::Pair<const Field *, String> Auth::getNameField(const StringView &value) const {
82 575 : if (_name) {
83 0 : return stappler::pair(_name, value.str<Interface>());
84 575 : } else if (_nameFieldCallback) {
85 0 : return _nameFieldCallback(*_scheme, value);
86 : } else {
87 575 : auto name = _scheme->getField("name");
88 575 : auto email = _scheme->getField("email");
89 575 : if (email) {
90 575 : String str = value.str<Interface>();
91 575 : if (stappler::valid::validateEmail(str)) {
92 0 : return stappler::pair(email, std::move(str));
93 : }
94 575 : }
95 575 : if (name) {
96 1150 : return stappler::pair(name, value.str<Interface>());
97 : }
98 : }
99 0 : return stappler::pair(nullptr, String());
100 : }
101 :
102 575 : const Field *Auth::getPasswordField() const {
103 575 : return _password;
104 : }
105 :
106 550 : bool Auth::authorizeWithPassword(const StringView &input, const Bytes &database, size_t tryCount) const {
107 550 : auto f = _password->getSlot<FieldPassword>();
108 550 : if (stappler::valid::validatePassord(input, database, f->salt)) {
109 550 : return true;
110 : }
111 0 : _application->error("Auth", "Login attempts", Value(config::AUTH_MAX_LOGIN_ATTEMPT - tryCount - 1));
112 0 : return false;
113 : }
114 :
115 575 : const Field *Auth::detectPasswordField(const Scheme &s) {
116 575 : if (auto f = s.getField("password")) {
117 575 : return f;
118 : } else {
119 0 : for (auto &it : s.getFields()) {
120 0 : if (it.second.getType() == Type::Bytes && it.second.getTransform() == Transform::Password) {
121 0 : return &it.second;
122 : }
123 : }
124 : }
125 0 : return nullptr;
126 : }
127 :
128 : }
|