jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/350448 )
Change subject: [IMPR] Add BotPasswords in generate_user_files.py
......................................................................
[IMPR] Add BotPasswords in generate_user_files.py
Support it by generating a user-password.py file
For each different username entered, ask if user wants to save a
BotPassword (BotPassword name, BotPassword pass)
and save it in a user-password.py file that contain
(u'myusername', BotPassword(u'mybotpasswordname',
u'mysecretbotpasswordpass'))
Doc:
https://www.mediawiki.org/wiki/Manual:Pywikibot/BotPasswords
Bug: T143905
Change-Id: I35e30b6b94a360c16d365499c78863ac3aac1663
---
M generate_user_files.py
M pywikibot/config2.py
M pywikibot/tools/__init__.py
3 files changed, 98 insertions(+), 11 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/generate_user_files.py b/generate_user_files.py
index 4de8a47..977dcc1 100755
--- a/generate_user_files.py
+++ b/generate_user_files.py
@@ -204,20 +204,43 @@
# family , you can use '*'
{usernames}
+# The list of BotPasswords is saved in another file. Import it if needed.
+# See
https://www.mediawiki.org/wiki/Manual:Pywikibot/BotPasswords to know how
+# use them.
+{botpasswords}
{config_text}"""
SMALL_CONFIG = ('# -*- coding: utf-8 -*-\n'
- u"from __future__ import absolute_import, unicode_literals\n"
- u"family = '{main_family}'\n"
+ 'from __future__ import absolute_import, unicode_literals\n'
+ "family = '{main_family}'\n"
"mylang = '{main_code}'\n"
- u"{usernames}\n")
+ '{usernames}\n'
+ '{botpasswords}\n')
+
+PASSFILE_CONFIG = """# This is an automatically generated file used to
store
+# BotPasswords.
+#
+# As a simpler (but less secure) alternative to OAuth, MediaWiki allows bot
+# users to uses BotPasswords to limit the permissions given to a bot.
+# When using BotPasswords, each instance gets keys. This combination can only
+# access the API, not the normal web interface.
+#
+# See
https://www.mediawiki.org/wiki/Manual:Pywikibot/BotPasswords for more
+# information.
+{botpasswords}"""
def create_user_config(args=None, force=False):
- """Create a user-config.py in base_dir."""
+ """
+ Create a user-config.py in base_dir.
+
+ Create a user-password.py if necessary.
+ """
_fnc = os.path.join(base_dir, "user-config.py")
- if file_exists(_fnc):
+ _fncpass = os.path.join(base_dir, 'user-password.py')
+ # TODO: T167573: better check for existing user-password file
+ if file_exists(_fnc) or file_exists(_fncpass):
return
if args and force and not config.verbose_output:
@@ -235,13 +258,48 @@
usernames += [get_site_and_lang(main_family, main_code,
main_username)]
+ botpasswords = []
if not main_username:
usernames = "# usernames['{0}']['{1}'] =
u'MyUsername'".format(
main_family, main_code)
else:
+ # For each different username entered, ask if user wants to save a
+ # BotPassword (username, BotPassword name, BotPassword pass)
+ seen = set()
+ for username in usernames:
+ if username[2] in seen:
+ continue
+ seen.add(username[2])
+ if pywikibot.input_yn('Do you want to add a BotPassword for {0}?'
+ .format(username[2]),
+ force=force, default=False):
+ if not botpasswords:
+ pywikibot.output(
+ 'See
https://www.mediawiki.org/wiki/'
+ 'Manual:Pywikibot/BotPasswords to know '
+ 'how to get codes.')
+ pywikibot.output('Please note that plain text in {0} and '
+ 'anyone with read access to that '
+ 'directory will be able read the file.'
+ .format(_fncpass))
+ message = 'BotPassword\'s "bot name" for
{0}'.format(
+ username[2])
+ botpasswordname = pywikibot.input(message, force=force)
+ message = 'BotPassword\'s "password" for BotPassword
"{0}" ' \
+ '(no characters will be shown)' \
+ .format(botpasswordname)
+ botpasswordpass = pywikibot.input(message, force=force,
+ password=True)
+ if botpasswordname and botpasswordpass:
+ botpasswords.append((username[2], botpasswordname,
+ botpasswordpass))
+
usernames = '\n'.join(
u"usernames['{0}']['{1}'] =
u'{2}'".format(*username)
for username in usernames)
+ botpasswords = '\n'.join(
+ "('{0}', BotPassword('{1}',
'{2}'))".format(*botpassword)
+ for botpassword in botpasswords)
config_text = ''
config_content = SMALL_CONFIG
@@ -288,12 +346,16 @@
pywikibot.exception()
try:
+ # Finally save user-config.py
with codecs.open(_fnc, "w", "utf-8") as f:
f.write(config_content.format(main_family=main_family,
main_code=main_code,
usernames=usernames,
- config_text=config_text))
-
+ config_text=config_text,
+ botpasswords='password_file = ' +
+
('"user-password.py"'
+ if botpasswords
+ else 'None')))
pywikibot.output(u"'%s' written." % _fnc)
except:
try:
@@ -301,6 +363,23 @@
except:
pass
raise
+
+ if botpasswords:
+ # Save if necessary user-password.py
+ try:
+ # First create an empty file with good permissions, before writing
+ # in it
+ with codecs.open(_fncpass, 'w', 'utf-8') as f:
+ f.write('')
+ pywikibot.tools.file_mode_checker(_fncpass, mode=0o600,
+ quiet=True)
+ with codecs.open(_fncpass, 'w', 'utf-8') as f:
+ f.write(PASSFILE_CONFIG.format(botpasswords=botpasswords))
+ pywikibot.tools.file_mode_checker(_fncpass, mode=0o600)
+ pywikibot.output("'{0}' written.".format(_fncpass))
+ except EnvironmentError:
+ os.remove(_fncpass)
+ raise
def main(*args):
@@ -341,6 +420,7 @@
# Only give option for directory change if user-config.py already exists
# in the directory. This will repeat if user-config.py also exists in
# the requested directory.
+ # TODO: T167573: check for user-password.py too
if not force or config.verbose_output:
pywikibot.output(u'\nYour default user directory is "%s"' %
base_dir)
while os.path.isfile(os.path.join(base_dir, "user-config.py")):
diff --git a/pywikibot/config2.py b/pywikibot/config2.py
index 78898cc..97203a3 100644
--- a/pywikibot/config2.py
+++ b/pywikibot/config2.py
@@ -218,11 +218,18 @@
# By default you are asked for a password on the terminal.
# A password file may be used, e.g. password_file = ".passwd".
# The path to the password file is relative to that of the user_config file.
-# The password file should consist of lines containing
-# Python tuples of any of the following formats:
+# The password file should consist of lines containing Python tuples of any
+# of the following formats:
# (code, family, username, password)
# (family, username, password)
# (username, password)
+# It's also possible (and safer) for bot users to use BotPasswords to limit
+# the permissions given to a bot. When using BotPasswords, each instance gets
+# keys. This combination can only access the API, not the normal web interface.
+# See
https://www.mediawiki.org/wiki/Manual:Pywikibot/BotPasswords to know how
+# use them. In this case, the password file should contein a BotPassword object
+# in the following format:
+# (username, BotPassword(botname, botpassword))
password_file = None
# edit summary to use if not supplied by bot script
diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py
index 7e1c9c1..4546304 100644
--- a/pywikibot/tools/__init__.py
+++ b/pywikibot/tools/__init__.py
@@ -1709,7 +1709,7 @@
return open_archive(filename, use_extension=use_extension)
-def file_mode_checker(filename, mode=0o600):
+def file_mode_checker(filename, mode=0o600, quiet=False):
"""Check file mode and update it, if needed.
@param filename: filename path
@@ -1723,7 +1723,7 @@
if stat.S_ISREG(st_mode) and (st_mode - stat.S_IFREG != mode):
os.chmod(filename, mode)
# re-read and check changes
- if os.stat(filename).st_mode != st_mode:
+ if os.stat(filename).st_mode != st_mode and not quiet:
warn(warn_str.format(filename, st_mode - stat.S_IFREG, mode))
--
To view, visit
https://gerrit.wikimedia.org/r/350448
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I35e30b6b94a360c16d365499c78863ac3aac1663
Gerrit-Change-Number: 350448
Gerrit-PatchSet: 23
Gerrit-Owner: Framawiki <framawiki(a)tools.wmflabs.org>
Gerrit-Reviewer: Dalba <dalba.wiki(a)gmail.com>
Gerrit-Reviewer: Framawiki <framawiki(a)tools.wmflabs.org>
Gerrit-Reviewer: Magul <tomasz.magulski(a)gmail.com>
Gerrit-Reviewer: Matěj Suchánek <matejsuchanek97(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Multichill <maarten(a)mdammers.nl>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: Zhuyifei1999 <zhuyifei1999(a)gmail.com>
Gerrit-Reviewer: jenkins-bot <>