Cicalese has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/358363 )
Change subject: Initial commit. ...................................................................... Initial commit. Change-Id: Idebbba10a54ede48ef74db3edbc04589eac85ca7 --- A CODE_OF_CONDUCT.md A COPYING A Gruntfile.js A extension.json A i18n/en.json A i18n/qqq.json A includes/ConfigEmailAuthorization.alias.php A includes/ConfigEmailAuthorization.php A includes/EmailAuthorization.php A includes/EmailAuthorizationHooks.php A package.json A resources/EmailAuthorization.css A sql/EmailAuthorization.sql 13 files changed, 877 insertions(+), 0 deletions(-) Approvals: Cicalese: Looks good to me, approved jenkins-bot: Verified diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d8e5d08 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +The development of this software is covered by a [Code of Conduct](https://www.mediawiki.org/wiki/Code_of_Conduct). diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5eb4ac0 --- /dev/null +++ b/COPYING @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 The MITRE Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..aa66d75 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,21 @@ +/*jshint node:true */ +module.exports = function ( grunt ) { + grunt.loadNpmTasks( 'grunt-jsonlint' ); + grunt.loadNpmTasks( 'grunt-banana-checker' ); + + grunt.initConfig( { + banana: { + all: 'i18n/' + }, + jsonlint: { + all: [ + '**/*.json', + '!node_modules/**', + '!vendor/**' + ] + } + } ); + + grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] ); + grunt.registerTask( 'default', 'test' ); +}; \ No newline at end of file diff --git a/extension.json b/extension.json new file mode 100644 index 0000000..2a80704 --- /dev/null +++ b/extension.json @@ -0,0 +1,49 @@ +{ + "name": "Email Authorization", + "version": "1.0", + "author": [ + "[https://www.mediawiki.org/wiki/User:Cindy.cicalese Cindy Cicalese]" + ], + "url": "https://www.mediawiki.org/wiki/Extension:Email_Authorization", + "descriptionmsg": "emailauthorization-desc", + "license-name": "MIT", + "type": "other", + "SpecialPages": { + "ConfigEmailAuthorization": "ConfigEmailAuthorization" + }, + "MessagesDirs": { + "EmailAuthorization": [ + "i18n" + ] + }, + "ExtensionMessagesFiles": { + "EmailAuthorizationAlias": "includes/ConfigEmailAuthorization.alias.php" + }, + "ResourceModules": { + "ext.EmailAuthorization": { + "styles": [ + "EmailAuthorization.css" + ], + "targets": [ + "desktop", + "mobile" + ] + } + }, + "ResourceFileModulePaths": { + "localBasePath": "resources", + "remoteExtPath": "EmailAuthorization/resources" + }, + "AutoloadClasses": { + "EmailAuthorization": "includes/EmailAuthorization.php", + "EmailAuthorizationHooks": "includes/EmailAuthorizationHooks.php", + "ConfigEmailAuthorization": "includes/ConfigEmailAuthorization.php" + }, + "Hooks": { + "PluggableAuthUserAuthorization": [ "EmailAuthorizationHooks::authorize" ], + "LoadExtensionSchemaUpdates": [ + "EmailAuthorizationHooks::loadExtensionSchemaUpdates" + ] + }, + "manifest_version": 1 +} diff --git a/i18n/en.json b/i18n/en.json new file mode 100644 index 0000000..9d6f22e --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,35 @@ +{ + "@metadata": { + "authors": [ + "cicalese" + ] + }, + "emailauthorization-desc": "Authorize users by email address", + "configemailauthorization": "Configure Email Authorization", + "configemailauthorization-instructions": "To add or revoke all email addresses in a domain use ''@domain'', where ''domain'' is the email domain. This will not affect other email addresses explicitly added in that domain.", + "configemailauthorization-authorized": "''$1'' is authorized.", + "configemailauthorization-notauthorized": "''$1'' is not authorized.", + "configemailauthorization-added": "Successfully authorized ''$1''.", + "configemailauthorization-alreadyauthorized": "''$1'' is already authorized.", + "configemailauthorization-revoked": "Successfully revoked authorization from ''$1''.", + "configemailauthorization-noauthfound": "No authorized email addresses or domains found.", + "configemailauthorization-nousersfound": "No users found.", + "configemailauthorization-label-email": "Email", + "configemailauthorization-label-username": "Username", + "configemailauthorization-label-realname": "Real Name", + "configemailauthorization-label-userpage": "User Page", + "configemailauthorization-label-authorized": "Authorized", + "configemailauthorization-value-domain": "all users with email addresses ending in $1", + "configemailauthorization-value-yes": "yes", + "configemailauthorization-value-no": "no", + "configemailauthorization-legend-search": "Search for email addresses", + "configemailauthorization-legend-add": "Add authorized email address or domain", + "configemailauthorization-legend-revoke": "Revoke authorized email address or domain", + "configemailauthorization-button-next": "Next", + "configemailauthorization-button-previous": "Previous", + "configemailauthorization-button-search": "Search", + "configemailauthorization-button-add": "Add", + "configemailauthorization-button-revoke": "Revoke", + "configemailauthorization-button-showauth": "Show authorized email addresses and domains", + "configemailauthorization-button-showall": "Show all wiki users" +} diff --git a/i18n/qqq.json b/i18n/qqq.json new file mode 100644 index 0000000..1ba050d --- /dev/null +++ b/i18n/qqq.json @@ -0,0 +1,35 @@ +{ + "@metadata": { + "authors": [ + "cicalese" + ] + }, + "emailauthorization-desc": "{{desc|name=Email Authorization|url=https://www.mediawiki.org/wiki/Extension:Email_Authorization}}", + "configemailauthorization": "Special page name", + "configemailauthorization-instructions": "Instructions", + "configemailauthorization-authorized": "Status message", + "configemailauthorization-notauthorized": "Status message", + "configemailauthorization-added": "Status message", + "configemailauthorization-alreadyauthorized": "Status message", + "configemailauthorization-revoked": "Status message", + "configemailauthorization-noauthfound": "Status message", + "configemailauthorization-nousersfound": "Status message", + "configemailauthorization-label-email": "Table column label", + "configemailauthorization-label-username": "Table column label", + "configemailauthorization-label-realname": "Table column label", + "configemailauthorization-label-userpage": "Table column label", + "configemailauthorization-label-authorized": "Table column label", + "configemailauthorization-value-domain": "Table value", + "configemailauthorization-value-yes": "Table value", + "configemailauthorization-value-no": "Table value", + "configemailauthorization-legend-search": "Form legend", + "configemailauthorization-legend-add": "Form legend", + "configemailauthorization-legend-revoke": "Form legend", + "configemailauthorization-button-next": "Button text", + "configemailauthorization-button-previous": "Button text", + "configemailauthorization-button-search": "Button text", + "configemailauthorization-button-add": "Button text", + "configemailauthorization-button-revoke": "Button text", + "configemailauthorization-button-showauth": "Button text", + "configemailauthorization-button-showall": "Button text" +} diff --git a/includes/ConfigEmailAuthorization.alias.php b/includes/ConfigEmailAuthorization.alias.php new file mode 100644 index 0000000..7b9c939 --- /dev/null +++ b/includes/ConfigEmailAuthorization.alias.php @@ -0,0 +1,30 @@ +<?php + +/* + * Copyright (c) 2017 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +$specialPageAliases = []; + +/** English */ +$specialPageAliases['en'] = [ + 'ConfigEmailAuthorization' => [ 'Configure Email Authorization' ] +]; diff --git a/includes/ConfigEmailAuthorization.php b/includes/ConfigEmailAuthorization.php new file mode 100644 index 0000000..8cc5749 --- /dev/null +++ b/includes/ConfigEmailAuthorization.php @@ -0,0 +1,544 @@ +<?php + +/* + * Copyright (c) 2017 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +class ConfigEmailAuthorization extends SpecialPage { + + function __construct() { + parent::__construct( 'ConfigEmailAuthorization', + 'configemailauthorization' ); + } + + function execute( $par ) { + if ( !$this->userCanExecute( $this->getUser() ) ) { + $this->displayRestrictionError(); + return; + } + + $request = $this->getRequest(); + $this->setHeaders(); + $this->getOutput()->addModuleStyles( 'ext.EmailAuthorization' ); + + $search = self::searchEmail( $request->getText( 'searchemail' ) ); + self::addEmail( $request->getText( 'addemail' ) ); + self::revokeEmail( $request->getText( 'revokeemail' ) ); + self::showAuthorizedUsers( $request->getText( 'authoffset' ) ); + self::showAllUsers( $request->getText( 'alloffset' ) ); + + $title = Title::newFromText( 'Special:' . __CLASS__ ); + $url = $title->getFullURL(); + + $html = Html::openElement( 'p' ) + . Html::openElement( 'b' ) + . wfMessage( 'configemailauthorization-instructions' )->parse() + . Html::closeElement( 'b' ) + . Html::closeElement( 'p' ); + $this->getOutput()->addHtml( $html ); + + $defaultAddEmail = ''; + if ( is_null( $search ) ) { + $defaultAddEmail = trim( $request->getText( 'revokeemail' ) ); + } elseif ( !$search ) { + $defaultAddEmail = trim( $request->getText( 'searchemail' ) ); + } + self::showAddForm( $url, $defaultAddEmail ); + + $defaultRevokeEmail = ''; + if ( is_null( $search ) ) { + $defaultRevokeEmail = trim( $request->getText( 'addemail' ) ); + } elseif ( $search ) { + $defaultRevokeEmail = trim( $request->getText( 'searchemail' ) ); + } + self::showRevokeForm( $url, $defaultRevokeEmail ); + + self::showSearchForm( $url ); + self::showAuthorizedUsersForm( $url ); + self::showAllUsersForm( $url ); + } + + private function displayMessage( $message ) { + $html = Html::openElement( 'p', [ + 'class' => 'emailauth-message' + ] ) + . $message + . Html::closeElement( 'p' ); + $this->getOutput()->addHtml( $html ); + } + + private function searchEmail( $email ) { + if ( !is_null( $email ) && strlen( $email ) > 0 ) { + $email = mb_strtolower( htmlspecialchars( trim( $email ), ENT_QUOTES ) ); + if ( EmailAuthorization::isEmailAuthorized( $email ) ) { + $this->displayMessage( + wfMessage( 'configemailauthorization-authorized', $email ) + ); + return true; + } else { + $this->displayMessage( + wfMessage( 'configemailauthorization-notauthorized', $email ) + ); + return false; + } + } + return null; + } + + private function addEmail( $email ) { + if ( !is_null( $email ) && strlen( $email ) > 0 ) { + $email = mb_strtolower( htmlspecialchars( trim( $email ), ENT_QUOTES ) ); + if ( self::insertEmail( $email ) ) { + $this->displayMessage( + wfMessage( 'configemailauthorization-added', $email ) + ); + wfRunHooks( 'EmailAuthorizationAdd', [ $email ] ); + } else { + $this->displayMessage( + wfMessage( 'configemailauthorization-alreadyauthorized', $email ) + ); + } + } + } + + private function revokeEmail( $email ) { + if ( !is_null( $email ) && strlen( $email ) > 0 ) { + $email = mb_strtolower( htmlspecialchars( trim( $email ), ENT_QUOTES ) ); + if ( self::deleteEmail( $email ) ) { + $this->displayMessage( + wfMessage( 'configemailauthorization-revoked', $email ) + ); + wfRunHooks( 'EmailAuthorizationRevoke', [ $email ] ); + } else { + $this->displayMessage( + wfMessage( 'configemailauthorization-notauthorized', $email ) + ); + } + } + } + + private function showAuthorizedUsers( $authoffset ) { + + if ( is_null( $authoffset ) || strlen( $authoffset ) == 0 || + !is_numeric( $authoffset ) || $authoffset < 0 ) { + return; + } + + $limit = 20; + + $emails = self::getAuthorizedEmails( $limit + 1, $authoffset ); + $next = false; + + if ( !$emails->valid() ) { + $authoffset = 0; + $emails = self::getAuthorizedEmails( $limit + 1, $authoffset ); + if ( !$emails->valid() ) { + $this->displayMessage( + wfMessage( 'configemailauthorization-noauthfound' ) + ); + return; + } + } + + $wikitext = '{| class="wikitable emailauth-wikitable"' . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-email' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-username' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-realname' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-userpage' ) . PHP_EOL; + + $index = 0; + $more = false; + foreach ( $emails as $email ) { + if ( $index < $limit ) { + $wikitext .= '|-' . PHP_EOL; + $email_addr = htmlspecialchars( $email->email, ENT_QUOTES ); + if ( strlen( $email_addr ) > 1 && $email_addr[0] == '@' ) { + $wikitext .= '|' + . wfMessage( 'configemailauthorization-value-domain', $email_addr ) + . PHP_EOL; + $wikitext .= '| ' . PHP_EOL; + $wikitext .= '| ' . PHP_EOL; + $wikitext .= '| ' . PHP_EOL; + } else { + $wikitext .= '|' . $email_addr . PHP_EOL; + $users = self::getUserInfo( $email_addr ); + if ( !$users->valid() ) { + $wikitext .= '| ' . PHP_EOL; + $wikitext .= '| ' . PHP_EOL; + $wikitext .= '| ' . PHP_EOL; + } else { + $first = true; + $wikitext .= '|'; + foreach ( $users as $user ) { + $user_name = htmlspecialchars( $user->user_name, ENT_QUOTES ); + if ( $first ) { + $first = false; + } else { + $wikitext .= '<br />'; + } + $wikitext .= $user_name; + } + $wikitext .= PHP_EOL; + $first = true; + $wikitext .= '|'; + foreach ( $users as $user ) { + $real_name = htmlspecialchars( $user->user_real_name, ENT_QUOTES ); + if ( $first ) { + $first = false; + } else { + $wikitext .= '<br />'; + } + $wikitext .= $real_name; + } + $wikitext .= PHP_EOL; + $first = true; + $wikitext .= '|'; + foreach ( $users as $user ) { + $user_name = htmlspecialchars( $user->user_name, ENT_QUOTES ); + if ( $first ) { + $first = false; + } else { + $wikitext .= '<br />'; + } + $wikitext .= '[[User:' . $user_name . ']]'; + } + $wikitext .= PHP_EOL; + } + } + $index ++; + } else { + $more = true; + } + } + + $wikitext .= '|}' . PHP_EOL; + $this->getOutput()->addWikiText( $wikitext ); + + if ( $authoffset > 0 || $more ) { + $this->addTableNavigation( $authoffset, $more, $limit, 'authoffset' ); + } + + $html = Html::element( 'hr' ); + $this->getOutput()->addHtml( $html ); + } + + private function showAllUsers( $alloffset ) { + + if ( is_null( $alloffset ) || strlen( $alloffset ) == 0 || + !is_numeric( $alloffset ) || $alloffset < 0 ) { + return; + } + + $limit = 20; + + $users = self::getUsers( $limit + 1, $alloffset ); + $next = false; + + if ( !$users->valid() ) { + $alloffset = 0; + $users = self::getUsers( $limit + 1, $alloffset ); + if ( !$users->valid() ) { + $this->displayMessage( + wfMessage( 'configemailauthorization-nousersfound' ) + ); + return; + } + } + + $wikitext = '{| class="wikitable emailauth-wikitable"' . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-email' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-username' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-realname' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-userpage' ) . PHP_EOL; + $wikitext .= + '!' . wfMessage( 'configemailauthorization-label-authorized' ) . PHP_EOL; + + $index = 0; + $more = false; + foreach ( $users as $user ) { + if ( $index < $limit ) { + $email = htmlspecialchars( $user->user_email, ENT_QUOTES ); + $user_name = htmlspecialchars( $user->user_name, ENT_QUOTES ); + $real_name = htmlspecialchars( $user->user_real_name, ENT_QUOTES ); + $email = htmlspecialchars( $user->user_email, ENT_QUOTES ); + $wikitext .= '|-' . PHP_EOL; + $wikitext .= '|' . $email . PHP_EOL; + $wikitext .= '|' . $user_name . PHP_EOL; + $wikitext .= '|' . $real_name . PHP_EOL; + $wikitext .= '|[[User:' . $user_name . ']]' . PHP_EOL; + if ( EmailAuthorization::isEmailAuthorized( $email ) ) { + $wikitext .= '| style="text-align:center;" | ' + . wfMessage( 'configemailauthorization-value-yes' ) + . PHP_EOL; + } else { + $wikitext .= '| style="text-align:center;" | ' + . wfMessage( 'configemailauthorization-value-no' ) + . PHP_EOL; + } + $index ++; + } else { + $more = true; + } + } + + $wikitext .= '|}' . PHP_EOL; + $this->getOutput()->addWikiText( $wikitext ); + + if ( $alloffset > 0 || $more ) { + $this->addTableNavigation( $alloffset, $more, $limit, 'alloffset' ); + } + + $html = Html::element( 'hr' ); + $this->getOutput()->addHtml( $html ); + } + + private function addTableNavigation( $offset, $more, $limit, $paramname ) { + + $title = Title::newFromText( 'Special:ConfigEmailAuthorization' ); + $url = $title->getFullURL(); + + $html = Html::openElement( 'table', [ + 'class' => 'emailauth-navigationtable' + ] ) + . Html::openElement( 'tr' ) + . Html::openElement( 'td' ); + + if ( $offset > 0 ) { + $prevurl = $url . '?' . $paramname . '=' . ( $offset - $limit ); + $html .= Html::openElement( 'a', [ + 'href' => $prevurl, + 'class' => 'emailauth-button' + ] ) + . wfMessage( 'configemailauthorization-button-previous' ) + . Html::closeElement( 'a' ); + } + + $html .= Html::closeElement( 'td' ) + . Html::openElement( 'td', [ + 'style' => 'text-align:right;' + ] ); + + if ( $more ) { + $nexturl = $url . '?' . $paramname . '=' . ( $offset + $limit ); + $html .= Html::openElement( 'a', [ + 'href' => $nexturl, + 'class' => 'emailauth-button' + ] ) + . wfMessage( 'configemailauthorization-button-next' ) + . Html::closeElement( 'a' ); + } + + $html .= Html::closeElement( 'td' ) + . Html::closeElement( 'tr' ) + . Html::closeElement( 'table' ); + $this->getOutput()->addHtml( $html ); + } + + private function showSearchForm( $url ) { + $html = Html::openElement( 'form', [ + 'method' => 'post', + 'action' => $url, + 'id' => 'SearchEmail' + ] ) + . Html::openElement( 'fieldset' ) + . Html::element( 'legend', null, + wfMessage( 'configemailauthorization-legend-search' ) . ':' ); + list( $label, $input ) = + Xml::inputLabelSep( 'Email address:', 'searchemail', 'searchemail', + 50 ); + $html .= $label . ' ' . $input . ' ' + . Xml::submitButton( + wfMessage( 'configemailauthorization-button-search' ), + [ 'class' => 'emailauth-button' ] ) + . Html::closeElement( 'fieldset' ) + . Html::closeElement( 'form' ); + $this->getOutput()->addHtml( $html ); + } + + private function showAddForm( $url, $default ) { + $html = Html::openElement( 'form', [ + 'method' => 'post', + 'action' => $url, + 'id' => 'AddEmail' + ] ) + . Html::openElement( 'fieldset' ) + . Html::element( 'legend', null, + wfMessage( 'configemailauthorization-legend-add' ) . ':' ); + list( $label, $input ) = + Xml::inputLabelSep( 'Email address:', 'addemail', 'addemail', 50, + $default ); + $html .= $label . ' ' . $input . ' ' + . Xml::submitButton( + wfMessage( 'configemailauthorization-button-add' ), + [ 'class' => 'emailauth-button' ] ) + . Html::closeElement( 'fieldset' ) + . Html::closeElement( 'form' ); + $this->getOutput()->addHtml( $html ); + } + + private function showRevokeForm( $url, $default ) { + $html = Html::openElement( 'form', [ + 'method' => 'post', + 'action' => $url, + 'id' => 'RevokeEmail' + ] ) + . Html::openElement( 'fieldset' ) + . Html::element( 'legend', null, + wfMessage( 'configemailauthorization-legend-revoke' ) . ':' ); + list( $label, $input ) = + Xml::inputLabelSep( 'Email address:', 'revokeemail', 'revokeemail', + 50, $default ); + $html .= $label . ' ' . $input . ' ' + . Xml::submitButton( + wfMessage( 'configemailauthorization-button-revoke' ), + [ 'class' => 'emailauth-button' ] ) + . Html::closeElement( 'fieldset' ) + . Html::closeElement( 'form' ); + $this->getOutput()->addHtml( $html ); + } + + private function showAuthorizedUsersForm( $url ) { + $html = Html::openElement( 'form', [ + 'method' => 'post', + 'action' => $url, + 'id' => 'ShowAuthorizedUsers', + 'style' => 'display:inline;' + ] ) + . Html::hidden( 'authoffset', 0 ) + . Xml::submitButton( + wfMessage( 'configemailauthorization-button-showauth' ), + [ 'class' => 'emailauth-button' ] ) + . Html::closeElement( 'form' ); + $this->getOutput()->addHtml( $html ); + } + + private function showAllUsersForm( $url ) { + $html = Html::openElement( 'form', [ + 'method' => 'post', + 'action' => $url, + 'id' => 'ShowAllUsers', + 'style' => 'display:inline;' + ] ) + . Html::hidden( 'alloffset', 0 ) + . Xml::submitButton( + wfMessage( 'configemailauthorization-button-showall' ), + [ 'class' => 'emailauth-button' ] ) + . Html::closeElement( 'form' ); + $this->getOutput()->addHtml( $html ); + } + + private static function getAuthorizedEmails( $limit, $authoffset ) { + $dbr = wfGetDB( DB_SLAVE ); + $emails = $dbr->select( + 'emailauth', + [ + 'email' + ], + [], + __METHOD__, + [ + 'ORDER BY' => 'email', + 'LIMIT' => $limit, + 'OFFSET' => $authoffset + ] + ); + return $emails; + } + + private static function getUsers( $limit, $alloffset ) { + $dbr = wfGetDB( DB_SLAVE ); + $users = $dbr->select( + 'user', + [ + 'user_name', + 'user_real_name', + 'user_email' + ], + [], + __METHOD__, + [ + 'ORDER BY' => 'user_email', + 'LIMIT' => $limit, + 'OFFSET' => $alloffset + ] + ); + return $users; + } + + private static function getUserInfo( $email ) { + $dbr = wfGetDB( DB_SLAVE ); + $users = $dbr->select( + 'user', + [ + 'user_name', + 'user_real_name' + ], + [ + 'user_email' => $email + ], + __METHOD__, + [ + 'ORDER BY' => 'user_name', + ] + ); + return $users; + } + + private static function insertEmail( $email ) { + $dbw = wfGetDB( DB_MASTER ); + $dbw->insert( + 'emailauth', + [ + 'email' => $email + ], + __METHOD__ + ); + if ( $dbw->affectedRows() === 1 ) { + return true; + } else { + return false; + } + } + + private static function deleteEmail( $email ) { + $dbw = wfGetDB( DB_MASTER ); + $dbw->delete( + 'emailauth', + [ + 'email' => $email + ], + __METHOD__ + ); + if ( $dbw->affectedRows() === 1 ) { + return true; + } else { + return false; + } + } +} diff --git a/includes/EmailAuthorization.php b/includes/EmailAuthorization.php new file mode 100644 index 0000000..9fa23be --- /dev/null +++ b/includes/EmailAuthorization.php @@ -0,0 +1,61 @@ +<?php + +/* + * Copyright (c) 2017 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +class EmailAuthorization { + + public static function isEmailAuthorized( $email ) { + $dbr = wfGetDB( DB_SLAVE ); + $row = $dbr->selectRow( + 'emailauth', + [ + 'email' + ], + [ + 'email' => $email + ], + __METHOD__ + ); + if ( $row !== false ) { + return true; + } + $index = strpos( $email, '@' ); + if ( $index !== false && $index < strlen( $email ) - 1 ) { + $domain = substr( $email, $index ); + $row = $dbr->selectRow( + 'emailauth', + [ + 'email' + ], + [ + 'email' => $domain + ], + __METHOD__ + ); + if ( $row !== false ) { + return true; + } + } + return false; + } +} diff --git a/includes/EmailAuthorizationHooks.php b/includes/EmailAuthorizationHooks.php new file mode 100644 index 0000000..2b70624 --- /dev/null +++ b/includes/EmailAuthorizationHooks.php @@ -0,0 +1,39 @@ +<?php + +/* + * Copyright (c) 2017 The MITRE Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +class EmailAuthorizationHooks { + + public static function loadExtensionSchemaUpdates( $updater ) { + $dir = $GLOBALS['wgExtensionDirectory'] . DIRECTORY_SEPARATOR . + 'EmailAuthorization' . DIRECTORY_SEPARATOR . 'sql' . DIRECTORY_SEPARATOR; + $updater->addExtensionTable( 'emailauth', + $dir . 'EmailAuthorization.sql', true ); + return true; + } + + public static function authorize( $user, &$authorized ) { + $authorized = EmailAuthorization::isEmailAuthorized( $user->mEmail ); + return $authorized; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..375c25d --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "private": true, + "scripts": { + "test": "grunt test" + }, + "devDependencies": { + "grunt": "1.0.1", + "grunt-banana-checker": "0.5.0", + "grunt-jsonlint": "1.1.0" + } +} \ No newline at end of file diff --git a/resources/EmailAuthorization.css b/resources/EmailAuthorization.css new file mode 100644 index 0000000..293b380 --- /dev/null +++ b/resources/EmailAuthorization.css @@ -0,0 +1,26 @@ +.emailauth-message { + background-color: #ddd; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 10px; + padding-right: 10px; +} + +.emailauth-wikitable { + width: 100%; +} + +.emailauth-navigationtable { + width: 100%; +} + +.emailauth-button { + font-size: 1em; + padding:5px 15px; + margin:5px 5px; + background:#ccc; + border:0 none; + cursor:pointer; + -webkit-border-radius: 5px; + border-radius: 5px; +} diff --git a/sql/EmailAuthorization.sql b/sql/EmailAuthorization.sql new file mode 100644 index 0000000..1f12cc7 --- /dev/null +++ b/sql/EmailAuthorization.sql @@ -0,0 +1,4 @@ +CREATE TABLE `emailauth` ( + `email` tinyblob NOT NULL, + PRIMARY KEY (`email`(50)) +) ENGINE=InnoDB DEFAULT CHARSET=binary; -- To view, visit https://gerrit.wikimedia.org/r/358363 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Idebbba10a54ede48ef74db3edbc04589eac85ca7 Gerrit-PatchSet: 8 Gerrit-Project: mediawiki/extensions/EmailAuthorization Gerrit-Branch: master Gerrit-Owner: Cicalese <cical...@mitre.org> Gerrit-Reviewer: Cicalese <cical...@mitre.org> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits