Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Memri
plugins
Gmail IMAP
Commits
499ff32a
Commit
499ff32a
authored
3 years ago
by
Eelco van der Wel
Browse files
Options
Download
Plain Diff
Merge branch 'revert-
3bf9897c
' into 'dev'
Revert "cvu with error message" See merge request plugins/gmail!3
parents
3bf9897c
75196a00
Pipeline
#3469
passed with stages
in 2 minutes and 46 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
cvu/passwordAuth.cvu
+2
-15
cvu/passwordAuth.cvu
gmail_importer/authenticator.py
+1
-22
gmail_importer/authenticator.py
nbs/authenticator.ipynb
+73
-145
nbs/authenticator.ipynb
with
76 additions
and
182 deletions
+76
-182
cvu/passwordAuth.cvu
+
2
-
15
View file @
499ff32a
...
...
@@ -10,21 +10,8 @@
layout: [
{ section: username, fields: identifier, exclude: labels }
{ section: password, fields: secret, exclude: labels }
{ section: error }
{ section: login }
]
error {
showTitle: false
HStack {
show: showError
Text {
text: "SomeError"
font: 16 semibold
color: #f00
}
}
}
login {
showTitle: false
...
...
@@ -35,7 +22,7 @@
padding: 20 0 20 0
onPress: [
setProperty {
subject: {{.
~account
}}
subject: {{.
view
}}
property: "status"
value: "ready"
}
...
...
@@ -59,4 +46,4 @@
}
}
}
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
gmail_importer/authenticator.py
+
1
-
22
View file @
499ff32a
...
...
@@ -38,25 +38,11 @@ class PasswordAuthenticator:
self
.
pluginRun
=
pluginRun
self
.
isTest
=
False
def
set_login_error
(
self
,
cvu_item
,
error_message
=
None
):
cvu_string
:
str
=
cvu_item
.
definition
if
error_message
:
cvu_string
=
cvu_string
.
replace
(
"show: showError"
,
"show: true"
)
cvu_string
=
cvu_string
.
replace
(
'text: "SomeError"'
,
f
'text: "
{
error_message
}
"'
)
cvu_string
else
:
cvu_string
=
cvu_string
.
replace
(
"show: showError"
,
"show: false"
)
cvu_item
.
definition
=
cvu_string
return
cvu_item
def
authenticate
(
self
,
plugin
):
self
.
request_user_credentials
()
login_success
=
False
for
tries_remaining
in
range
(
self
.
MAX_LOGIN_ATTEMPTS
):
for
_
in
range
(
self
.
MAX_LOGIN_ATTEMPTS
):
username
,
password
=
self
.
poll_credentials
()
print
(
username
,
password
)
try
:
...
...
@@ -66,12 +52,6 @@ class PasswordAuthenticator:
except
Exception
as
e
:
print
(
e
)
print
(
"Login failed, invalid credentials."
)
cvu
=
self
.
pluginRun
.
get_edges
(
"view"
)[
0
]
cvu
=
self
.
set_login_error
(
cvu
,
error_message
=
f
"Invalid credentials,
{
tries_remaining
}
attempts remaining."
)
self
.
client
.
update_item
(
cvu
)
self
.
pluginRun
.
status
=
RUN_USER_ACTION_NEEDED
self
.
client
.
update_item
(
self
.
pluginRun
)
login_success
=
False
if
not
login_success
:
...
...
@@ -81,7 +61,6 @@ class PasswordAuthenticator:
def
request_user_credentials
(
self
):
cvu
=
get_cvu
(
LOGIN_CVU
)
cvu
=
self
.
set_login_error
(
cvu
,
error_message
=
None
)
self
.
client
.
create
(
cvu
)
self
.
pluginRun
.
add_edge
(
"view"
,
cvu
)
self
.
client
.
create_edge
(
self
.
pluginRun
.
get_edges
(
"view"
)[
0
])
...
...
This diff is collapsed.
Click to expand it.
nbs/authenticator.ipynb
+
73
-
145
View file @
499ff32a
...
...
@@ -2,18 +2,20 @@
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"%autoreload 2\n",
"# default_exp authenticator"
],
"outputs": [],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# export \n",
"# hide\n",
...
...
@@ -28,13 +30,13 @@
"import time\n",
"\n",
"import gmail_importer"
],
"outputs": [],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# export\n",
"LOGIN_CVU = \"passwordAuth.cvu\"\n",
...
...
@@ -44,12 +46,11 @@
" path = Path(base_path) / name\n",
" cvu_str = read_file(path)\n",
" return CVUStoredDefinition(definition=cvu_str, name=name, externalId=name)"
],
"outputs": [],
"metadata": {}
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Password Authenticator\n",
"\n",
...
...
@@ -59,12 +60,13 @@
"\n",
"Inheriting class should implement:\n",
"- get_token() that tests username-password combination or gets a new session token to be used for future calls\n"
],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# export\n",
"# hide\n",
...
...
@@ -79,25 +81,11 @@
" self.pluginRun = pluginRun\n",
" self.isTest = False\n",
"\n",
" def set_login_error(self, cvu_item, error_message=None):\n",
" cvu_string: str = cvu_item.definition\n",
" if error_message:\n",
" cvu_string = cvu_string.replace(\"show: showError\", \"show: true\")\n",
" cvu_string = cvu_string.replace('text: \"SomeError\"', f'text: \"{error_message}\"')\n",
" cvu_string\n",
" else:\n",
" cvu_string = cvu_string.replace(\"show: showError\", \"show: false\")\n",
"\n",
" cvu_item.definition = cvu_string\n",
" return cvu_item\n",
"\n",
"\n",
"\n",
" def authenticate(self, plugin):\n",
" self.request_user_credentials()\n",
"\n",
" login_success = False\n",
" for
tries_remaining
in range(self.MAX_LOGIN_ATTEMPTS):\n",
" for
_
in range(self.MAX_LOGIN_ATTEMPTS):\n",
" username, password = self.poll_credentials()\n",
" print(username, password)\n",
" try:\n",
...
...
@@ -107,12 +95,6 @@
" except Exception as e:\n",
" print(e)\n",
" print(\"Login failed, invalid credentials.\")\n",
"\n",
" cvu = self.pluginRun.get_edges(\"view\")[0]\n",
" cvu = self.set_login_error(cvu, error_message=f\"Invalid credentials, {tries_remaining} attempts remaining.\")\n",
" self.client.update_item(cvu)\n",
" self.pluginRun.status = RUN_USER_ACTION_NEEDED\n",
" self.client.update_item(self.pluginRun)\n",
" login_success = False\n",
" \n",
" if not login_success:\n",
...
...
@@ -122,7 +104,6 @@
" \n",
" def request_user_credentials(self):\n",
" cvu = get_cvu(LOGIN_CVU)\n",
" cvu = self.set_login_error(cvu, error_message=None)\n",
" self.client.create(cvu)\n",
" self.pluginRun.add_edge(\"view\", cvu)\n",
" self.client.create_edge(self.pluginRun.get_edges(\"view\")[0])\n",
...
...
@@ -142,13 +123,24 @@
" if self.pluginRun.status == RUN_USER_ACTION_COMPLETED:\n",
" account = self.pluginRun.account[0]\n",
" return account.identifier, account.secret\n"
],
"outputs": [],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from pymemri.plugin.pluginbase import PluginBase\n",
"from pymemri.plugin.schema import PluginRun, Account\n",
...
...
@@ -183,34 +175,39 @@
"pod_client.create(run)\n",
"pod_client.create(account)\n",
"pod_client.create_edge(run.get_edges(\"account\")[0])"
],
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"True"
]
},
"metadata": {},
"execution_count": 19
}
],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create Plugin\n",
"plugin = MyAuthenticatedPlugin(client=pod_client, pluginRun=run)"
],
"outputs": [],
"metadata": {}
"plugin = MyAuthenticatedPlugin(client=pod_client, pluginRun=run) "
]
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<Response [400]> b'Failure: Property externalId not defined in Schema (attempted to use it for json value \"passwordAuth.cvu\")'\n",
"<Response [404]> b'Endpoint not found'\n",
"polling for credentials...\n",
"polling for credentials...\n",
"polling for credentials...\n",
"polling for credentials...\n",
"polling for credentials...\n",
"polling for credentials...\n",
"polling for credentials...\n"
]
}
],
"source": [
"# Start plugin in background thread\n",
"def run_thread():\n",
...
...
@@ -219,22 +216,21 @@
" \n",
"thread = threading.Thread(target=run_thread)\n",
"thread.start()"
],
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"output_type": "stream",
"text": [
"polling for credentials...\n",
"polling for credentials...\n"
"done!\n"
]
}
],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 23,
"source": [
"# Enter password and check if plugin is authenticated\n",
"\n",
...
...
@@ -254,91 +250,23 @@
"simulate_enter_password(pod_client, run.id) \n",
"time.sleep(4)\n",
"assert plugin.logged_in"
],
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"username password\n",
"done!\n"
]
}
],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 1,
"source": [
"a = \"1234\"\n",
"b = a.replace(\"4\", \"5\")\n",
"b"
],
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"'1235'"
]
},
"metadata": {},
"execution_count": 1
}
],
"metadata": {}
},
{
"cell_type": "code",
"execution_count": 29,
"source": [
"run.view"
],
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"[CVUStoredDefinition (#c1618a8e06821e359a6ed2628e26f942),\n",
" CVUStoredDefinition (#2f180ce9b41e6ee863f17f003706280c)]"
]
},
"metadata": {},
"execution_count": 29
}
],
"metadata": {}
]
},
{
"cell_type": "code",
"execution_count": null,
"
source
":
[]
,
"
metadata
":
{}
,
"outputs": [],
"
metadata
":
{}
"
source
":
[]
}
],
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3.9.5 64-bit ('pymemri': conda)"
},
"language_info": {
"name": "python",
"version": "3.9.5",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
},
"interpreter": {
"hash": "da389e7ea39fce59e0a26507aab1708acf3a78fe76e774d0d7a5c909df6385c9"
"display_name": "Python 3",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
\ No newline at end of file
}
%% Cell type:code id: tags:
```
```
python
%
load_ext
autoreload
%
autoreload
2
# default_exp authenticator
```
%% Cell type:code id: tags:
```
```
python
# export
# hide
import
abc
from
time
import
sleep
from
pathlib
import
Path
from
pymemri.data.basic
import
read_file
from
pymemri.plugin.states
import
RUN_USER_ACTION_NEEDED
,
RUN_USER_ACTION_COMPLETED
from
pymemri.data.schema
import
CVUStoredDefinition
import
time
import
gmail_importer
```
%% Cell type:code id: tags:
```
```
python
# export
LOGIN_CVU
=
"passwordAuth.cvu"
CVU_BASE_PATH
=
Path
(
gmail_importer
.
__file__
).
parent
.
parent
/
"cvu"
def
get_cvu
(
name
,
base_path
=
CVU_BASE_PATH
):
path
=
Path
(
base_path
)
/
name
cvu_str
=
read_file
(
path
)
return
CVUStoredDefinition
(
definition
=
cvu_str
,
name
=
name
,
externalId
=
name
)
```
%% Cell type:markdown id: tags:
## Password Authenticator
Password Authenticator provides an easy interface to setup standard username-password authentication with 3rd party services.
Simply calling
`authenticate()`
should load the related account with required credentials.
Inheriting class should implement:
-
get_token() that tests username-password combination or gets a new session token to be used for future calls
%% Cell type:code id: tags:
```
```
python
# export
# hide
class
PasswordAuthenticator
:
MAX_LOGIN_ATTEMPTS
=
10
SLEEP_INTERVAL
=
1.0
MAX_POLL_TIME
=
1000
def
__init__
(
self
,
client
,
pluginRun
):
self
.
client
=
client
self
.
pluginRun
=
pluginRun
self
.
isTest
=
False
def set_login_error(self, cvu_item, error_message=None):
cvu_string: str = cvu_item.definition
if error_message:
cvu_string = cvu_string.replace("show: showError", "show: true")
cvu_string = cvu_string.replace('text: "SomeError"', f'text: "{error_message}"')
cvu_string
else:
cvu_string = cvu_string.replace("show: showError", "show: false")
cvu_item.definition = cvu_string
return cvu_item
def
authenticate
(
self
,
plugin
):
self
.
request_user_credentials
()
login_success
=
False
for
tries_remaining
in range(self.MAX_LOGIN_ATTEMPTS):
for
_
in
range
(
self
.
MAX_LOGIN_ATTEMPTS
):
username
,
password
=
self
.
poll_credentials
()
print
(
username
,
password
)
try
:
plugin
.
login
(
username
,
password
)
login_success
=
True
break
except
Exception
as
e
:
print
(
e
)
print
(
"Login failed, invalid credentials."
)
cvu = self.pluginRun.get_edges("view")[0]
cvu = self.set_login_error(cvu, error_message=f"Invalid credentials, {tries_remaining} attempts remaining.")
self.client.update_item(cvu)
self.pluginRun.status = RUN_USER_ACTION_NEEDED
self.client.update_item(self.pluginRun)
login_success
=
False
if
not
login_success
:
self
.
pluginRun
.
status
=
"error"
self
.
client
.
update_item
(
self
.
pluginRun
)
raise
RuntimeError
(
"Reached max login attempts."
)
def
request_user_credentials
(
self
):
cvu
=
get_cvu
(
LOGIN_CVU
)
cvu = self.set_login_error(cvu, error_message=None)
self
.
client
.
create
(
cvu
)
self
.
pluginRun
.
add_edge
(
"view"
,
cvu
)
self
.
client
.
create_edge
(
self
.
pluginRun
.
get_edges
(
"view"
)[
0
])
self
.
pluginRun
.
status
=
RUN_USER_ACTION_NEEDED
self
.
client
.
update_item
(
self
.
pluginRun
)
def
poll_credentials
(
self
):
# request username and password from the user client
# WAIT HERE = BLOCK
start_time
=
time
.
time
()
while
True
:
if
time
.
time
()
-
start_time
>
self
.
MAX_POLL_TIME
:
raise
RuntimeError
(
"Stop polling, max time reached."
)
print
(
"polling for credentials..."
)
sleep
(
self
.
SLEEP_INTERVAL
)
self
.
pluginRun
=
self
.
client
.
get
(
self
.
pluginRun
.
id
)
if
self
.
pluginRun
.
status
==
RUN_USER_ACTION_COMPLETED
:
account
=
self
.
pluginRun
.
account
[
0
]
return
account
.
identifier
,
account
.
secret
```
%% Cell type:code id: tags:
```
```
python
from
pymemri.plugin.pluginbase
import
PluginBase
from
pymemri.plugin.schema
import
PluginRun
,
Account
from
pymemri.pod.client
import
PodClient
import
threading
class
MyAuthenticatedPlugin
(
PluginBase
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
().
__init__
(
*
args
,
**
kwargs
)
self
.
logged_in
=
False
self
.
authenticator
=
PasswordAuthenticator
(
kwargs
[
"client"
],
kwargs
[
"pluginRun"
])
def
login
(
self
,
username
,
password
):
if
not
(
username
==
"username"
and
password
==
"password"
):
raise
ValueError
(
"Wrong credentials."
)
def
run
(
self
):
self
.
authenticator
.
authenticate
(
self
)
self
.
logged_in
=
True
print
(
"done!"
)
def
add_to_schema
(
self
):
pass
pod_client
=
PodClient
()
run
=
PluginRun
(
""
,
""
,
""
)
account
=
Account
(
service
=
"myAuthenticatedPlugin"
)
run
.
add_edge
(
"account"
,
account
)
run
.
status
=
"start"
pod_client
.
create
(
run
)
pod_client
.
create
(
account
)
pod_client
.
create_edge
(
run
.
get_edges
(
"account"
)[
0
])
```
%% Output
True
%% Cell type:code id: tags:
```
```
python
# Create Plugin
plugin
=
MyAuthenticatedPlugin
(
client
=
pod_client
,
pluginRun
=
run
)
```
%% Cell type:code id: tags:
```
```
python
# Start plugin in background thread
def
run_thread
():
plugin
.
run
()
assert
plugin
.
logged_in
thread
=
threading
.
Thread
(
target
=
run_thread
)
thread
.
start
()
```
%% Output
<Response [400]> b'Failure: Property externalId not defined in Schema (attempted to use it for json value "passwordAuth.cvu")'
<Response [404]> b'Endpoint not found'
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
polling for credentials...
%% Cell type:code id: tags:
```
```
python
# Enter password and check if plugin is authenticated
def
simulate_enter_password
(
pod_client
,
run_id
):
run
=
pod_client
.
get
(
run_id
)
account
=
run
.
account
[
0
]
username
=
"username"
password
=
"password"
account
.
identifier
=
username
account
.
secret
=
password
run
.
status
=
"ready"
pod_client
.
update_item
(
account
)
pod_client
.
update_item
(
run
)
simulate_enter_password
(
pod_client
,
run
.
id
)
time
.
sleep
(
4
)
assert
plugin
.
logged_in
```
%% Output
username password
done!
%% Cell type:code id: tags:
```
a = "1234"
b = a.replace("4", "5")
b
```
%% Output
'1235'
%% Cell type:code id: tags:
```
run.view
```
%% Output
[CVUStoredDefinition (#c1618a8e06821e359a6ed2628e26f942),
CVUStoredDefinition (#2f180ce9b41e6ee863f17f003706280c)]
%% Cell type:code id: tags:
```
```
python
```
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment