Skip to content

Commit

Permalink
Remove cassandra queries to user_keys_hash
Browse files Browse the repository at this point in the history
they are never read anymore since 'onboarding' / auto-connect was removed in #1005
  • Loading branch information
jschaul committed Dec 6, 2022
1 parent 1518191 commit a6dc3e5
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 121 deletions.
1 change: 1 addition & 0 deletions changelog.d/5-internal/remove-hashed-key-queries
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove cassandra queries to the user_keys_hash table, as they are never read anymore since 'onboarding' / auto-connect was removed in https://github.com/wireapp/wire-server/pull/1005
2 changes: 2 additions & 0 deletions services/brig/schema/src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,7 @@ main = do

-- FUTUREWORK: undo V41 (searchable flag); we stopped using it in
-- https://github.com/wireapp/wire-server/pull/964
--
-- FUTUREWORK after July 2023: integrate V_FUTUREWORK here.
]
`finally` Log.close l
48 changes: 48 additions & 0 deletions services/brig/schema/src/V_FUTUREWORK.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{-# LANGUAGE QuasiQuotes #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module V_FUTUREWORK
( migration,
)
where

import Cassandra.Schema
import Imports
import Text.RawString.QQ

-- user_keys_hash usage was removed in https://github.com/wireapp/wire-server/pull/2902
--
-- However, it's dangerous to remove a cassandra table together with the usage, as
-- during deployment, there is a time window where the schema migration has run, but the
-- old code still serves traffic, which then leads to 5xxs and user-observable errors.
-- Therefore the policy is to wait a reasonable amount of time (6 months) to allow all
-- installations to upgrade before removing the database tables. See also
-- backwards-incompatbile schema migration docs in
-- https://docs.wire.com/developer/developer/cassandra-interaction.html?highlight=backwards+incompatbile#backwards-incompatible-schema-changes
--
-- FUTUREWORK: uncomment the code below after July 2023, rename this module with a version number, and
-- integrate it inside Main.hs and App.hs
migration :: Migration
migration = undefined

-- Migration FUTUREWORK_NUMBER "Drop deprecated user_keys_hashed table" $ do
-- schema'
-- [r|
-- DROP TABLE IF EXISTS user_keys_hash
-- |]
67 changes: 1 addition & 66 deletions services/brig/src/Brig/Data/UserKey.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,17 @@ module Brig.Data.UserKey
lookupKey,
deleteKey,
deleteKeyForUser,
lookupPhoneHashes,
)
where

import Brig.App (Env, digestSHA256)
import Brig.App (Env)
import Brig.Data.Instances ()
import qualified Brig.Data.User as User
import Brig.Email
import Brig.Phone
import Cassandra
import Control.Lens (view)
import qualified Data.ByteString as B
import Data.ByteString.Lazy (toStrict)
import Data.Id
import qualified Data.Multihash.Digest as MH
import qualified Data.Text.Encoding as T
import Imports
import OpenSSL.EVP.Digest (digestBS)
import Wire.API.User (fromEmail)

-- | A natural identifier (i.e. unique key) of a user.
Expand All @@ -60,35 +53,6 @@ instance Eq UserKey where
(UserPhoneKey k) == (UserPhoneKey k') = k == k'
_ == _ = False

data UKHashType
= UKHashPhone
| UKHashEmail
deriving (Eq)

instance Cql UKHashType where
ctype = Tagged IntColumn

fromCql (CqlInt i) = case i of
0 -> pure UKHashPhone
1 -> pure UKHashEmail
n -> Left $ "unexpected hashtype: " ++ show n
fromCql _ = Left "userkeyhashtype: int expected"

toCql UKHashPhone = CqlInt 0
toCql UKHashEmail = CqlInt 1

newtype UserKeyHash = UserKeyHash MH.MultihashDigest

instance Cql UserKeyHash where
ctype = Tagged BlobColumn

fromCql (CqlBlob lbs) = case MH.decode (toStrict lbs) of
Left e -> Left ("userkeyhash: " ++ e)
Right h -> pure $ UserKeyHash h
fromCql _ = Left "userkeyhash: expected blob"

toCql (UserKeyHash d) = CqlBlob $ MH.encode (MH.algorithm d) (MH.digest d)

userEmailKey :: Email -> UserKey
userEmailKey = UserEmailKey . mkEmailKey

Expand Down Expand Up @@ -154,15 +118,10 @@ lookupKey k =

insertKey :: (MonadClient m, MonadReader Env m) => UserId -> UserKey -> m ()
insertKey u k = do
hk <- hashKey k
let kt = foldKey (\(_ :: Email) -> UKHashEmail) (\(_ :: Phone) -> UKHashPhone) k
retry x5 $ write insertHashed (params LocalQuorum (hk, kt, u))
retry x5 $ write keyInsert (params LocalQuorum (keyText k, u))

deleteKey :: (MonadClient m, MonadReader Env m) => UserKey -> m ()
deleteKey k = do
hk <- hashKey k
retry x5 $ write deleteHashed (params LocalQuorum (Identity hk))
retry x5 $ write keyDelete (params LocalQuorum (Identity $ keyText k))

-- | Delete `UserKey` for `UserId`
Expand All @@ -180,21 +139,6 @@ deleteKeyForUser uid k = do
Just keyUid | keyUid == uid -> deleteKey k
_ -> pure ()

hashKey :: MonadReader Env m => UserKey -> m UserKeyHash
hashKey uk = do
d <- view digestSHA256
let d' = digestBS d $ T.encodeUtf8 (keyText uk)
pure . UserKeyHash $
MH.MultihashDigest MH.SHA256 (B.length d') d'

lookupPhoneHashes :: MonadClient m => [ByteString] -> m [(ByteString, UserId)]
lookupPhoneHashes hp =
mapMaybe mk <$> retry x1 (query selectHashed (params One (Identity hashed)))
where
hashed = fmap (\h -> UserKeyHash $ MH.MultihashDigest MH.SHA256 (B.length h) h) hp
mk (UserKeyHash d, UKHashPhone, u) = Just (MH.digest d, u)
mk (_, _, _) = Nothing

--------------------------------------------------------------------------------
-- Queries

Expand All @@ -206,12 +150,3 @@ keySelect = "SELECT user FROM user_keys WHERE key = ?"

keyDelete :: PrepQuery W (Identity Text) ()
keyDelete = "DELETE FROM user_keys WHERE key = ?"

insertHashed :: PrepQuery W (UserKeyHash, UKHashType, UserId) ()
insertHashed = "INSERT INTO user_keys_hash(key, key_type, user) VALUES (?, ?, ?)"

deleteHashed :: PrepQuery W (Identity UserKeyHash) ()
deleteHashed = "DELETE FROM user_keys_hash WHERE key = ?"

selectHashed :: PrepQuery R (Identity [UserKeyHash]) (UserKeyHash, UKHashType, UserId)
selectHashed = "SELECT key, key_type, user FROM user_keys_hash WHERE key IN ?"
5 changes: 0 additions & 5 deletions tools/db/move-team/src/ParseSchema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,6 @@ main = do
-- PRIMARY KEY (key :: text) (Brig.Data.UserKey)
-- FUTUREWORK: do we need it? can we do better than a full table scan?
mkChunk' "brig" "user_keys" "[Int32]" "keys" "key in ?",
-- brig.user_keys_hash
-- FUTUREWORK: do we need it?
-- can we do better than a full table scan?
-- mkChunk' "brig" "user_keys_hash" "[UserKeyHash]" "keys" "key in ?"
mkChunk' "brig" "user_keys_hash" "[Int32]" "keys" "key in ?",
-- brig.vcodes
-- galley.billing_team_member
-- PRIMARY KEY (team, user)
Expand Down
48 changes: 0 additions & 48 deletions tools/db/move-team/src/Schema.hs
Original file line number Diff line number Diff line change
Expand Up @@ -496,52 +496,6 @@ importBrigUserKeys Env {..} path = do
putStrLn $ "Skipping because not found: " <> path
pure ()

-- brig.user_keys_hash

type RowBrigUserKeysHash = (Maybe Blob, Maybe Int32, Maybe UUID)

selectBrigUserKeysHash :: PrepQuery R (Identity [Int32]) RowBrigUserKeysHash
selectBrigUserKeysHash = "SELECT key, key_type, user FROM user_keys_hash WHERE key in ?"

readBrigUserKeysHash :: Env -> [Int32] -> ConduitM () [RowBrigUserKeysHash] IO ()
readBrigUserKeysHash Env {..} keys =
transPipe (runClient envBrig) $
paginateC selectBrigUserKeysHash (paramsP LocalQuorum (pure keys) envPageSize) x5

selectBrigUserKeysHashAll :: PrepQuery R () RowBrigUserKeysHash
selectBrigUserKeysHashAll = "SELECT key, key_type, user FROM user_keys_hash"

readBrigUserKeysHashAll :: Env -> ConduitM () [RowBrigUserKeysHash] IO ()
readBrigUserKeysHashAll Env {..} =
transPipe (runClient envBrig) $
paginateC selectBrigUserKeysHashAll (paramsP LocalQuorum () envPageSize) x5

exportBrigUserKeysHashFull :: Env -> FilePath -> IO ()
exportBrigUserKeysHashFull env path = do
putStrLn $ "Exporting " <> "brig.user_keys_hash" <> " to " <> path
withBinaryFile path WriteMode $ \handle ->
runConduit $
readBrigUserKeysHashAll env
.| sinkJsonLines handle

insertBrigUserKeysHash :: PrepQuery W RowBrigUserKeysHash ()
insertBrigUserKeysHash =
"INSERT INTO user_keys_hash (key, key_type, user) VALUES (?, ?, ?)"

importBrigUserKeysHash :: Env -> FilePath -> IO ()
importBrigUserKeysHash Env {..} path = do
exists <- doesFileExist path
if exists
then do
putStrLn $ "Importing " <> path <> " to " <> "brig.user_keys_hash"
withBinaryFile path ReadMode $ \handle ->
runConduit $
sourceJsonLines handle
.| transPipe (runClient envBrig) (sinkTableRows insertBrigUserKeysHash)
else do
putStrLn $ "Skipping because not found: " <> path
pure ()

-- galley.billing_team_member

type RowGalleyBillingTeamMember = (Maybe UUID, Maybe UUID)
Expand Down Expand Up @@ -1244,7 +1198,6 @@ importAllTables env@Env {..} = do
importBrigUser env (envTargetPath </> "brig.user")
importBrigUserHandle env (envTargetPath </> "brig.user_handle")
importBrigUserKeys env (envTargetPath </> "brig.user_keys")
importBrigUserKeysHash env (envTargetPath </> "brig.user_keys_hash")
importGalleyBillingTeamMember env (envTargetPath </> "galley.billing_team_member")
importGalleyClients env (envTargetPath </> "galley.clients")
importGalleyConversation env (envTargetPath </> "galley.conversation")
Expand Down Expand Up @@ -1273,7 +1226,6 @@ exportAllTablesFull env@Env {..} = do
exportBrigUserFull env (envTargetPath </> "brig.user")
exportBrigUserHandleFull env (envTargetPath </> "brig.user_handle")
exportBrigUserKeysFull env (envTargetPath </> "brig.user_keys")
exportBrigUserKeysHashFull env (envTargetPath </> "brig.user_keys_hash")
exportGalleyBillingTeamMemberFull env (envTargetPath </> "galley.billing_team_member")
exportGalleyClientsFull env (envTargetPath </> "galley.clients")
exportGalleyConversationFull env (envTargetPath </> "galley.conversation")
Expand Down
2 changes: 0 additions & 2 deletions tools/db/move-team/src/Work.hs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ runFullScans env@Env {..} users = do
.| mapC (filter (haveId . view _2))

-- FUTUREWORK: no need to read this table, it can be populated from `brig.user`
appendJsonLines (envTargetPath </> "brig.user_keys_hash") $
readBrigUserKeysHashAll env
appendJsonLines (envTargetPath </> "spar.user") $
readSparUserAll env
.| mapC (filter (haveId . view _3))
Expand Down

0 comments on commit a6dc3e5

Please sign in to comment.