diff --git a/system/typemill/Controllers/ControllerApiTestmail.php b/system/typemill/Controllers/ControllerApiTestmail.php new file mode 100644 index 0000000..e68c1b1 --- /dev/null +++ b/system/typemill/Controllers/ControllerApiTestmail.php @@ -0,0 +1,61 @@ +settings['mailfrom']) or !filter_var($this->settings['mailfrom'], FILTER_VALIDATE_EMAIL)) + { + $response->getBody()->write(json_encode([ + 'message' => Translations::translate('The from mail is missing or it is not a valid e-mail address.') + ])); + + return $response->withHeader('Content-Type', 'application/json')->withStatus(400); + } + + $user = new User(); + $username = $request->getAttribute('c_username'); + + if(!$user->setUser($username)) + { + $response->getBody()->write(json_encode([ + 'message' => Translations::translate('We did not find the a user or usermail.') + ])); + + return $response->withHeader('Content-Type', 'application/json')->withStatus(400); + } + + $userdata = $user->getUserData(); + + $mail = new SimpleMail($this->settings); + + $subject = Translations::translate('Testmail from Typemill'); + $message = Translations::translate('This is a testmail from Typemill and if you read this e-mail, then everything works fine.'); + + $send = $mail->send($userdata['email'], $subject, $message); + + if(!$send) + { + $response->getBody()->write(json_encode([ + 'message' => Translations::translate('We could not send the testmail to your e-mail address. Reason: ') . $mail->error + ])); + + return $response->withHeader('Content-Type', 'application/json')->withStatus(500); + } + + $response->getBody()->write(json_encode([ + 'message' => Translations::translate('The testmail has been send, please check your inbox and your spam-folder to varify that you received the mail.') + ])); + + return $response->withHeader('Content-Type', 'application/json'); + } +} \ No newline at end of file diff --git a/system/typemill/Controllers/ControllerWebAuth.php b/system/typemill/Controllers/ControllerWebAuth.php index 36c2671..6359fa8 100644 --- a/system/typemill/Controllers/ControllerWebAuth.php +++ b/system/typemill/Controllers/ControllerWebAuth.php @@ -25,7 +25,7 @@ class ControllerWebAuth extends Controller $input = $request->getParsedBody(); $validation = new Validation(); $securitylog = $this->settings['securitylog'] ?? false; - $authcodeactive = $this->settings['authcode'] ?? false; + $authcodeactive = $this->isAuthcodeActive($this->settings); $authtitle = Translations::translate('Verification code missing?'); $authtext = Translations::translate('If you did not receive an email with the verification code, then the username or password you entered was wrong. Please try again.'); @@ -108,8 +108,6 @@ class ControllerWebAuth extends Controller $send = $mail->send($userdata['email'], $subject, $message); - $send = true; - if(!$send) { $authtitle = Translations::translate('Error sending email'); @@ -158,6 +156,21 @@ class ControllerWebAuth extends Controller } + private function isAuthcodeActive($settings) + { + if( + isset($settings['authcode']) && + $settings['authcode'] && + isset($settings['mailfrom']) && + filter_var($settings['mailfrom'], FILTER_VALIDATE_EMAIL) + ) + { + return true; + } + + return false; + } + # login a user with valid authcode public function loginWithAuthcode(Request $request, Response $response) { diff --git a/system/typemill/author/js/vue-forms.js b/system/typemill/author/js/vue-forms.js index 5e4765f..b686dd3 100644 --- a/system/typemill/author/js/vue-forms.js +++ b/system/typemill/author/js/vue-forms.js @@ -32,14 +32,13 @@ app.component('component-textarea', { + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -81,8 +80,7 @@ app.component('component-codearea', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> - + @input="update($event, name)">

{{ errors[name] }}

@@ -141,7 +139,7 @@ app.component('component-select', { @change="update($event,name)"> - +

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -173,7 +171,7 @@ app.component('component-checkbox', { v-model="checked" @change="update(checked, name)"> {{ $filters.translate(checkboxlabel) }} - +

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -209,7 +207,7 @@ app.component('component-checkboxlist', { v-model="checkedoptions" @change="update(checkedoptions, name)"> {{ $filters.translate(option) }} - +

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -249,7 +247,7 @@ app.component('component-radio', { v-model="picked" @change="update(picked, name)"> {{ $filters.translate(option) }} - +

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -277,7 +275,7 @@ app.component('component-number', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

`, @@ -308,7 +306,7 @@ app.component('component-date', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

@@ -342,7 +340,7 @@ app.component('component-email', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

@@ -375,7 +373,7 @@ app.component('component-tel', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

@@ -409,7 +407,7 @@ app.component('component-url', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

@@ -442,7 +440,7 @@ app.component('component-color', { :name="name" :placeholder="placeholder" :value="value" - @input="update($event, name)"> + @input="update($event, name)">

{{ errors[name] }}

{{ $filters.translate(description) }}

diff --git a/system/typemill/author/js/vue-system.js b/system/typemill/author/js/vue-system.js index da87e5f..7a5b276 100644 --- a/system/typemill/author/js/vue-system.js +++ b/system/typemill/author/js/vue-system.js @@ -17,6 +17,13 @@ const app = Vue.createApp({ :userroles="userroles" :value="formData[fieldname]" v-bind="subfieldDefinition"> + + + @@ -85,6 +92,32 @@ const app = Vue.createApp({ this.currentTab = tab; this.reset(); }, + testmail: function() + { + this.reset(); + var self = this; + + tmaxios.post('/api/v1/testmail',{ + 'url': data.urlinfo.route, + }) + .then(function (response) + { + self.messageClass = 'bg-teal-500'; + self.message = response.data.message; + }) + .catch(function (error) + { + if(error.response) + { + self.message = handleErrorMessage(error); + self.messageClass = 'bg-rose-500'; + if(error.response.data.errors !== undefined) + { + self.errors = error.response.data.errors; + } + } + }); + }, save: function() { this.reset(); @@ -109,7 +142,7 @@ const app = Vue.createApp({ self.errors = error.response.data.errors; } } - }); + }); }, reset: function() { diff --git a/system/typemill/routes/api.php b/system/typemill/routes/api.php index f47f867..7abf57c 100644 --- a/system/typemill/routes/api.php +++ b/system/typemill/routes/api.php @@ -19,6 +19,7 @@ use Typemill\Controllers\ControllerApiAuthorArticle; use Typemill\Controllers\ControllerApiAuthorBlock; use Typemill\Controllers\ControllerApiAuthorMeta; use Typemill\Controllers\ControllerApiAuthorShortcode; +use Typemill\Controllers\ControllerApiTestmail; $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) { @@ -35,6 +36,7 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) { $group->post('/plugin', ControllerApiSystemPlugins::class . ':updatePlugin')->setName('api.plugin.set')->add(new ApiAuthorization($acl, 'system', 'update')); # admin $group->post('/extensions', ControllerApiSystemExtensions::class . ':activateExtension')->setName('api.extension.activate')->add(new ApiAuthorization($acl, 'system', 'update')); # admin $group->post('/versioncheck', ControllerApiSystemVersions::class . ':checkVersions')->setName('api.versioncheck')->add(new ApiAuthorization($acl, 'system', 'update')); # admin + $group->post('/testmail', ControllerApiTestmail::class . ':send')->setName('api.testmail')->add(new ApiAuthorization($acl, 'system', 'update')); # admin $group->get('/users/getbynames', ControllerApiSystemUsers::class . ':getUsersByNames')->setName('api.usersbynames')->add(new ApiAuthorization($acl, 'user', 'update')); # admin $group->get('/users/getbyemail', ControllerApiSystemUsers::class . ':getUsersByEmail')->setName('api.usersbyemail')->add(new ApiAuthorization($acl, 'user', 'update')); # admin $group->get('/users/getbyrole', ControllerApiSystemUsers::class . ':getUsersByRole')->setName('api.usersbyrole')->add(new ApiAuthorization($acl, 'user', 'update')); # admin diff --git a/system/typemill/settings/system.yaml b/system/typemill/settings/system.yaml index 324e6e6..f495185 100644 --- a/system/typemill/settings/system.yaml +++ b/system/typemill/settings/system.yaml @@ -164,22 +164,22 @@ fieldsetmail: legend: Email fields: mailfrom: - type: text + type: email label: 'Mail From (required)' placeholder: sender@yourmail.org - maxlength: 60 - description: 'Enter an email address that should send emails (sender).' + maxlength: 100 + description: 'Enter an email address that sends the e-mails (sender). The e-mail-feature will be used for recovery and verification e-mails. Send a testmail to your user-account to verify that you receive the e-mails.' mailfromname: type: text label: 'Mail From Name (optional)' placeholder: sender name - maxlength: 60 + maxlength: 100 description: 'Optionally enter a name for the sender address. If not set, the from-address will be visible.' replyto: type: text label: 'Reply To (optional)' placeholder: noreply@yourmail.org - maxlength: 60 + maxlength: 100 description: 'Optionally enter a "reply to" address for answers from the receiver. If not set, answers will go to the from-address.' fieldsetrecover: type: fieldset @@ -189,7 +189,7 @@ fieldsetrecover: type: checkbox label: 'Recover password' checkboxlabel: 'Activate a password recovery in the login form.' - description: "Be aware that some providers might reject emails send with this feature (php-mail)." + description: "From mail is required for this feature. Send a testmail before you use this feature." recoversubject: type: text label: 'Email subject' @@ -204,15 +204,11 @@ fieldsetsecurity: type: fieldset legend: Security fields: - securitylog: - type: checkbox - label: 'Security log' - checkboxlabel: 'Track spam and suspicious actions in a logfile' authcode: type: checkbox label: 'Login Verification (recommended)' checkboxlabel: 'Verify your login with a 5-digit code send by email.' - description: 'Please test this with your account. If you do not get an email, make sure you have ftp-access to disable the feature in the settings.yaml manually. The verification code will be valid for 5 minutes. Be aware that device fingerprints will be stored in the user accounts. Make sure this complies with privacy legislation in your country.' + description: 'From mail is required for this feature. Send a testmail before you use this feature. Make sure you have ftp-access to disable the feature in settings.yaml on failure. The verification code will be valid for 5 minutes. Be aware that device fingerprints will be stored in the user accounts.' authcaptcha: type: radio label: 'Use captcha in authentication forms' @@ -220,6 +216,10 @@ fieldsetsecurity: disabled: 'Disable' standard: 'Always show' aftererror: 'Show after first wrong input' + securitylog: + type: checkbox + label: 'Security log' + checkboxlabel: 'Track spam and suspicious actions in a logfile' fieldsetdeveloper: type: fieldset legend: "Developer" @@ -242,18 +242,19 @@ fieldsetdeveloper: headersoff: type: checkbox label: "Disable Custom Headers" - checkboxlabel: "Disable all custom headers of Typemill and send your own headers instead." - corsdomains: - type: textarea - label: "Allowed Domains for API-Access (CORS)" - placeholder: 'https://my-website-that-uses-the-api.org,https://another-website-using-the-api.org' - description: "Add all domains separated with comma, that should have access to the Typemill API. Domains will be added to the cors-header." - cspdomains: - type: textarea - label: "Allowed Domains for Content on Typemill (CSP)" - placeholder: 'https://www.google.com,*google.com' - description: "Add all domains separated with comma, that you want to integrate on your Typemill website. Domains will be added to the csp-header. Usually done with plugins and themes, but add manually if something is blocked." + checkboxlabel: "Disable all custom headers of Typemill (except cors) and send your own headers instead." cspdisabled: type: checkbox label: "Disable CSP Headers" - checkboxlabel: "Disable all csp (content security policy) headers for this website." \ No newline at end of file + checkboxlabel: "Disable all csp headers (content security policy) for this website." + cspdomains: + type: textarea + label: "Allowed Domains for Content on Typemill (CSP-Headers)" + placeholder: 'https://www.google.com,*google.com' + description: "List all domains, separated by commas, to allow content integration, such as iframes, on your Typemill website. Domains will be added to the csp-header. Usually done with plugins and themes, but add manually if something is blocked." + corsdomains: + type: textarea + label: "Allowed Domains for API-Access (CORS-Headers)" + placeholder: 'https://my-website-that-uses-the-api.org,https://another-website-using-the-api.org' + description: "List all domains, separated by comma, that should have access to the Typemill API. Domains will be added to the cors-header." + \ No newline at end of file