summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--migrations/20220809225706_add_user_id_check_to_insert_or_update_device.down.sql4
-rw-r--r--migrations/20220809225706_add_user_id_check_to_insert_or_update_device.up.sql47
-rw-r--r--tests/conftest.py11
-rw-r--r--tests/test_auth_device.py15
4 files changed, 77 insertions, 0 deletions
diff --git a/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.down.sql b/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.down.sql
new file mode 100644
index 0000000..51d1743
--- /dev/null
+++ b/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.down.sql
@@ -0,0 +1,4 @@
+drop function insert_or_update_device(device_id, user_id, text, text, device_push_info,
+ device_command[], jsonb, out device);
+alter function insert_or_update_device_1(device_id, user_id, text, text, device_push_info,
+ device_command[], jsonb, out device) rename to insert_or_update_device;
diff --git a/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.up.sql b/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.up.sql
new file mode 100644
index 0000000..06dbb94
--- /dev/null
+++ b/migrations/20220809225706_add_user_id_check_to_insert_or_update_device.up.sql
@@ -0,0 +1,47 @@
+alter function insert_or_update_device(device_id, user_id, text, text, device_push_info,
+ device_command[], jsonb, out device) rename to insert_or_update_device_1;
+
+create function insert_or_update_device(
+ p_device_id device_id,
+ p_user_id user_id,
+ p_name text,
+ p_type text,
+ p_push device_push_info,
+ p_available_commands device_command[],
+ p_location jsonb,
+ out result device)
+ returns setof device
+ language plpgsql
+ as $$
+ begin
+ update device
+ set name = coalesce(p_name, name),
+ type = coalesce(p_type, type),
+ push = coalesce(p_push, push),
+ available_commands = coalesce(p_available_commands, available_commands),
+ push_expired = push_expired and p_push is null,
+ location = coalesce(p_location, location)
+ where device_id = p_device_id and user_id = p_user_id
+ returning *
+ into result;
+
+ if not found then
+ begin
+ insert into device (device_id, user_id, name, type, push, push_expired,
+ available_commands, location)
+ values (p_device_id, p_user_id, p_name, p_type, p_push, p_push is null,
+ p_available_commands, coalesce(p_location, '{}'::jsonb))
+ returning *
+ into result;
+ exception
+ when unique_violation then
+ -- almost certainly updating another user's device, or we have
+ -- a broken RNG on the system. return nothing to signal either
+ -- error.
+ return;
+ end;
+ end if;
+
+ return next;
+ end
+ $$;
diff --git a/tests/conftest.py b/tests/conftest.py
index bf877e2..487eff9 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -55,6 +55,17 @@ def _account(client, primary, email, mail_server):
email1 = f"test.account-{os.urandom(8).hex()}@test-auth"
email2 = f"test.account2-{os.urandom(8).hex()}@test-auth"
+@pytest.fixture(scope="class")
+def account_plain(request, mail_server):
+ for a in _account(AuthClient(), True, email1, mail_server):
+ yield a
+ break
+@pytest.fixture(scope="class")
+def account2_plain(request, mail_server):
+ for a in _account(AuthClient(), True, email2, mail_server):
+ yield a
+ break
+
@pytest.fixture(params=[True, False], ids=["primary", "secondary"], scope="class")
def account(request, mail_server):
for a in _account(AuthClient(), request.param, email1, mail_server):
diff --git a/tests/test_auth_device.py b/tests/test_auth_device.py
index 5ec42f3..c978d87 100644
--- a/tests/test_auth_device.py
+++ b/tests/test_auth_device.py
@@ -192,6 +192,21 @@ def test_change(account_or_rt, populate_devices):
assert mdevs1[i1]['pushPublicKey'] or '' == mdevs2[i2]['pushPublicKey'] or ''
assert mdevs1[i1]['pushAuthKey'] or '' == mdevs2[i2]['pushAuthKey'] or ''
+def test_change_foreign(account_plain, account2_plain):
+ dev = account_plain.post_a("/account/device", device_data[0])
+ dev['name'] = 'foo'
+ del dev['isCurrentDevice']
+ del dev['lastAccessTime']
+ del dev['pushEndpointExpired']
+ with pytest.raises(ClientError) as e:
+ account2_plain.post_a("/account/device", dev)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 123,
+ 'error': 'Bad Request',
+ 'message': 'unknown device'
+ }
+
def test_invoke_noauth(client):
body = {"target": "0" * 32, "command": "foo", "payload": {}, "ttl": 10}
with pytest.raises(ClientError) as e: