kopia lustrzana https://github.com/halcy/Mastodon.py
Improve auth support
rodzic
5b328d479c
commit
24c686f6b2
|
@ -486,8 +486,7 @@ class Mastodon:
|
|||
"""
|
||||
return Mastodon.__SUPPORTED_MASTODON_VERSION
|
||||
|
||||
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob",
|
||||
scopes=__DEFAULT_SCOPES, force_login=False):
|
||||
def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None):
|
||||
"""
|
||||
Returns the url that a client needs to request an oauth grant from the server.
|
||||
|
||||
|
@ -501,6 +500,10 @@ class Mastodon:
|
|||
|
||||
Pass force_login if you want the user to always log in even when already logged
|
||||
into web mastodon (i.e. when registering multiple different accounts in an app).
|
||||
|
||||
State is the oauth `state`parameter to pass to the server. It is strongly suggested
|
||||
to use a random, nonguessable value (i.e. nothing meaningful and no incrementing ID)
|
||||
to preserve security guarantees. It can be left out for non-web login flows.
|
||||
"""
|
||||
if client_id is None:
|
||||
client_id = self.client_id
|
||||
|
@ -515,12 +518,11 @@ class Mastodon:
|
|||
params['redirect_uri'] = redirect_uris
|
||||
params['scope'] = " ".join(scopes)
|
||||
params['force_login'] = force_login
|
||||
params['state'] = state
|
||||
formatted_params = urlencode(params)
|
||||
return "".join([self.api_base_url, "/oauth/authorize?", formatted_params])
|
||||
|
||||
def log_in(self, username=None, password=None,
|
||||
code=None, redirect_uri="urn:ietf:wg:oauth:2.0:oob", refresh_token=None,
|
||||
scopes=__DEFAULT_SCOPES, to_file=None):
|
||||
def log_in(self, username=None, password=None, code=None, redirect_uri="urn:ietf:wg:oauth:2.0:oob", refresh_token=None, scopes=__DEFAULT_SCOPES, to_file=None):
|
||||
"""
|
||||
Get the access token for a user.
|
||||
|
||||
|
@ -588,6 +590,25 @@ class Mastodon:
|
|||
|
||||
return response['access_token']
|
||||
|
||||
def revoke_access_token(self):
|
||||
"""
|
||||
Revoke the oauth token the user is currently authenticated with, effectively removing
|
||||
the apps access and requiring the user to log in again.
|
||||
"""
|
||||
if self.access_token is None:
|
||||
raise MastodonIllegalArgumentError("Not logged in, do not have a token to revoke.")
|
||||
if self.client_id is None or self.client_secret is None:
|
||||
raise MastodonIllegalArgumentError("Client authentication (id + secret) is required to revoke tokens.")
|
||||
params = collections.OrderedDict([])
|
||||
params['client_id'] = self.client_id
|
||||
params['client_secret'] = self.client_secret
|
||||
params['token'] = self.access_token
|
||||
self.__api_request('POST', '/oauth/revoke', params)
|
||||
|
||||
# We are now logged out, clear token and logged in id
|
||||
self.access_token = None
|
||||
self.__logged_in_id = None
|
||||
|
||||
@api_version("2.7.0", "2.7.0", "2.7.0")
|
||||
def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=__DEFAULT_SCOPES, to_file=None):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
interactions:
|
||||
- request:
|
||||
body: username=mastodonpy_test_2%40localhost%3A3000&password=5fc638e0e53eafd9c4145b6bb852667d&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=password&client_id=__MASTODON_PY_TEST_CLIENT_ID&client_secret=__MASTODON_PY_TEST_CLIENT_SECRET&scope=read+write+follow+push
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '271'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: POST
|
||||
uri: http://localhost:3000/oauth/token
|
||||
response:
|
||||
body:
|
||||
string: '{"access_token":"s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk","token_type":"Bearer","scope":"read
|
||||
write follow push","created_at":1668370881}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-pCi2AQ9aKYXwS29cp2OHAg=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"b4c5259bc2edbe94aab5df0f3b8ba79a"
|
||||
Pragma:
|
||||
- no-cache
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 086350f4-00fc-4d82-a5ce-2b557df59682
|
||||
X-Runtime:
|
||||
- '0.040539'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: client_id=__MASTODON_PY_TEST_CLIENT_ID&client_secret=__MASTODON_PY_TEST_CLIENT_SECRET&token=s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer s3ZSxpaa2Uhe9EcHankvkfaQZQGiWpdEWIhX7GuhDlk
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '135'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: POST
|
||||
uri: http://localhost:3000/oauth/revoke
|
||||
response:
|
||||
body:
|
||||
string: '{}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- max-age=0, private, must-revalidate
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-PqM4ChK427oGZ5jIKprkYQ=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
ETag:
|
||||
- W/"44136fa355b3678a1146ad16f7e8649e"
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 36ec7e63-b15b-487a-aa4a-c396db945794
|
||||
X-Runtime:
|
||||
- '0.010431'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
- request:
|
||||
body: status=illegal+access+detected
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '30'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: POST
|
||||
uri: http://localhost:3000/api/v1/statuses
|
||||
response:
|
||||
body:
|
||||
string: '{"error":"The access token is invalid"}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-UClOh6+Y0zf3a4O/ysqT/w=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Pragma:
|
||||
- no-cache
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
WWW-Authenticate:
|
||||
- Bearer realm="Doorkeeper", error="invalid_token", error_description="The access
|
||||
token is invalid"
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- ab1f9d04-149b-431a-b2b0-79921d45f3bc
|
||||
X-Runtime:
|
||||
- '0.005292'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
- request:
|
||||
body: status=illegal+access+detected
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '30'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
User-Agent:
|
||||
- tests/v311
|
||||
method: POST
|
||||
uri: http://localhost:3000/api/v1/statuses
|
||||
response:
|
||||
body:
|
||||
string: '{"error":"The access token is invalid"}'
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Content-Security-Policy:
|
||||
- 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
|
||||
''self'' http://localhost:3000; img-src ''self'' https: data: blob: http://localhost:3000;
|
||||
style-src ''self'' http://localhost:3000 ''nonce-ZTmQUUs9q7lX74Aa3bTgzA=='';
|
||||
media-src ''self'' https: data: http://localhost:3000; frame-src ''self''
|
||||
https:; manifest-src ''self'' http://localhost:3000; connect-src ''self''
|
||||
data: blob: http://localhost:3000 http://localhost:3000 ws://localhost:4000
|
||||
ws://localhost:3035 http://localhost:3035; script-src ''self'' ''unsafe-inline''
|
||||
''unsafe-eval'' http://localhost:3000; child-src ''self'' blob: http://localhost:3000;
|
||||
worker-src ''self'' blob: http://localhost:3000'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Pragma:
|
||||
- no-cache
|
||||
Referrer-Policy:
|
||||
- strict-origin-when-cross-origin
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Accept, Origin
|
||||
WWW-Authenticate:
|
||||
- Bearer realm="Doorkeeper", error="invalid_token", error_description="The access
|
||||
token is invalid"
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Download-Options:
|
||||
- noopen
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Permitted-Cross-Domain-Policies:
|
||||
- none
|
||||
X-Request-Id:
|
||||
- 9a7ad262-0d94-4df6-92a5-a670d6515979
|
||||
X-Runtime:
|
||||
- '0.004613'
|
||||
X-XSS-Protection:
|
||||
- 1; mode=block
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
|
@ -22,14 +22,37 @@ def test_log_in_none(api_anonymous):
|
|||
with pytest.raises(MastodonIllegalArgumentError):
|
||||
api_anonymous.log_in()
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_log_in_password(api_anonymous):
|
||||
token = api_anonymous.log_in(
|
||||
username='mastodonpy_test_2@localhost:3000',
|
||||
password='5fc638e0e53eafd9c4145b6bb852667d')
|
||||
password='5fc638e0e53eafd9c4145b6bb852667d'
|
||||
)
|
||||
assert token
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_revoke(api_anonymous):
|
||||
token = api_anonymous.log_in(
|
||||
username='mastodonpy_test_2@localhost:3000',
|
||||
password='5fc638e0e53eafd9c4145b6bb852667d'
|
||||
)
|
||||
api_anonymous.revoke_access_token()
|
||||
|
||||
try:
|
||||
api_anonymous.toot("illegal access detected")
|
||||
assert False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
||||
api_revoked_token = Mastodon(access_token = token)
|
||||
try:
|
||||
api_anonymous.toot("illegal access detected")
|
||||
assert False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
||||
@pytest.mark.vcr()
|
||||
def test_log_in_password_incorrect(api_anonymous):
|
||||
with pytest.raises(MastodonIllegalArgumentError):
|
||||
|
|
Ładowanie…
Reference in New Issue