diff options
-rw-r--r-- | migrations/20220809225706_add_user_id_check_to_insert_or_update_device.down.sql | 4 | ||||
-rw-r--r-- | migrations/20220809225706_add_user_id_check_to_insert_or_update_device.up.sql | 47 | ||||
-rw-r--r-- | tests/conftest.py | 11 | ||||
-rw-r--r-- | tests/test_auth_device.py | 15 |
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: |