Skip to content

Commit

Permalink
Add ability to set names on tokens
Browse files Browse the repository at this point in the history
fixes mujx#38
  • Loading branch information
Konstantinos Sideris committed Aug 3, 2021
1 parent 4545408 commit 788773b
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 6 deletions.
15 changes: 14 additions & 1 deletion dashboard/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ function getTokens() {
});
}

function updateToken(opts) {
return m.request({
method: "POST",
url: baseUrl() + "/auth/token",
background: true,
body: opts,
headers: {
authorization: storage.getHeaderToken()
}
});
}

function deleteToken(tokenId) {
return m.request({
method: "DELETE",
Expand Down Expand Up @@ -244,5 +256,6 @@ export {
getUserTags,
getUserProjects,
getLeaderboards,
getCommitLog
getCommitLog,
updateToken
};
58 changes: 57 additions & 1 deletion dashboard/src/modals/TokenList.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import m from "mithril";
import $ from "jquery";
import _ from "lodash";

import * as api from "../api";
import utils from "../utils";
Expand Down Expand Up @@ -34,7 +35,7 @@ function renderModal(tokens) {
document.body.appendChild(modal);
}

availableTokens = tokens;
availableTokens = _.orderBy(tokens, ["tknId"]);

m.render(modal, m(Modal));

Expand Down Expand Up @@ -122,15 +123,70 @@ const Modal = {
"thead",
m("tr", [
m("th", { scope: "col" }, "ID"),
m("th", { scope: "col" }, "Name"),
m("th", { scope: "col" }, "Last usage"),
m("th", { scope: "col" }, "")
])
),
m(
"tbody",
availableTokens.map(t => {
const defaultName = "-";

return m("tr", [
m("td", { scope: "row" }, t.tknId.substring(0, 6)),
m(
"td",
{
scope: "row",
onclick: function (e) {
const el = e.target;
const input = document.createElement("input");
input.maxLength = 42;
input.value = el.innerHTML;

input.onkeydown = function (event) {
if (event.key == "Enter") {
this.blur();
}
};

input.onblur = function () {
el.innerHTML = input.value
? input.value
: defaultName;
input.replaceWith(el);

// Update the token name.
if (input.value && input.value !== t.tknId) {
api
.updateToken({
tokenId: t.tknId,
tokenName: input.value
})
.then(api.getTokens)
.then(function (tokens) {
renderModal(tokens);
})
.catch(function (e) {
console.log("Failed to update the token");
if (e && e.response) {
console.log(e.response);
return;
}
utils.showError(
"Failed to update the token"
);
});
}
};

el.replaceWith(input);
input.focus();
}
},
t.tknName ? t.tknName : defaultName
),
m(
"td",
t.lastUsage ? utils.formatDate(t.lastUsage) : "Not used"
Expand Down
2 changes: 2 additions & 0 deletions migrations/00002-add-token-name.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE auth_tokens ADD token_name TEXT;
ALTER TABLE auth_tokens ADD token_description TEXT;
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pkgs.stdenv.mkDerivation {
pkgs.hlint
pkgs.pgcli
pkgs.cabal2nix
pkgs.ormolu
];

shellHook = ''
Expand Down
7 changes: 7 additions & 0 deletions src/Haka/Database.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import Haka.Types
StoredUser (..),
TimelineRow (..),
TokenData (..),
TokenMetadata (..),
)
import qualified Haka.Utils as Utils
import qualified Hasql.Pool as HqPool
Expand Down Expand Up @@ -128,6 +129,9 @@ class (Monad m, MonadThrow m) => Db m where
-- | Get total time between the given time ranges.
getTotalTimeBetween :: HqPool.Pool -> V.Vector (Text, Text, UTCTime, UTCTime) -> m [Int64]

-- | Update token metadata set by the user.
updateTokenMetadata :: HqPool.Pool -> Text -> TokenMetadata -> m ()

instance Db IO where
getUser pool token = do
res <- HqPool.use pool (Sessions.getUser token)
Expand Down Expand Up @@ -225,6 +229,9 @@ instance Db IO where
-- We return in reverse order because we insert with descending but we sort in ascending.
res <- HqPool.use pool (Sessions.getTotalTimeBetween ranges)
either (throw . SessionException) (pure . reverse) res
updateTokenMetadata pool user metadata = do
res <- HqPool.use pool (Sessions.updateTokenMetadata user metadata)
either (throw . SessionException) pure res

mkTokenData :: Text -> IO TokenData
mkTokenData user = do
Expand Down
4 changes: 4 additions & 0 deletions src/Haka/Db/Sessions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Haka.Types
StoredUser (..),
TimelineRow (..),
TokenData (..),
TokenMetadata (..),
)
import qualified Haka.Utils as Utils
import Hasql.Session (Session, statement)
Expand All @@ -31,6 +32,9 @@ import PostgreSQL.Binary.Data (UUID)
updateTokenUsage :: Text -> Session ()
updateTokenUsage tkn = statement tkn Statements.updateTokenUsage

updateTokenMetadata :: Text -> TokenMetadata -> Session ()
updateTokenMetadata user metadata = statement (tokenId metadata, user, tokenName metadata) Statements.updateTokenMetadata

listApiTokens :: Text -> Session [StoredApiToken]
listApiTokens usr = statement usr Statements.listApiTokens

Expand Down
20 changes: 19 additions & 1 deletion src/Haka/Db/Statements.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,30 @@ updateTokenUsage = Statement query params D.noResult True
params :: E.Params Text
params = E.param (E.nonNullable E.text)

updateTokenMetadata :: Statement (Text, Text, Text) ()
updateTokenMetadata = Statement query params D.noResult True
where
query :: ByteString
query = [r| UPDATE auth_tokens SET token_name = $3 WHERE token = $1 AND owner = $2; |]

params :: E.Params (Text, Text, Text)
params =
contrazip3
(E.param (E.nonNullable E.text))
(E.param (E.nonNullable E.text))
(E.param (E.nonNullable E.text))

listApiTokens :: Statement Text [StoredApiToken]
listApiTokens = Statement query params result True
where
query :: ByteString
query =
[r|
select
token, last_usage::timestamp
token,
last_usage::timestamp,
token_name,
token_description
from
auth_tokens
where
Expand All @@ -74,6 +90,8 @@ listApiTokens = Statement query params result True
StoredApiToken
<$> (D.column . D.nonNullable) D.text
<*> (D.column . D.nullable) D.timestamptz
<*> (D.column . D.nullable) D.text
<*> (D.column . D.nullable) D.text

result :: D.Result [StoredApiToken]
result = D.rowList storedApiToken
Expand Down
32 changes: 30 additions & 2 deletions src/Haka/Handlers/Authentication.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Haka.Types
( ApiToken,
StoredApiToken,
TokenData (..),
TokenMetadata (..),
)
import Haka.Utils (getRefreshToken)
import Katip
Expand Down Expand Up @@ -104,6 +105,13 @@ type DeleteToken =
:> Header "Authorization" ApiToken
:> DeleteNoContent

type UpdateToken =
"auth"
:> "token"
:> Header "Authorization" ApiToken
:> ReqBody '[JSON] TokenMetadata
:> PostNoContent

type API =
Login
:<|> RefreshToken
Expand All @@ -112,6 +120,7 @@ type API =
:<|> DeleteToken
:<|> Logout
:<|> Register
:<|> UpdateToken

getStoredApiTokensHandler :: Maybe ApiToken -> AppM [StoredApiToken]
getStoredApiTokensHandler Nothing = throw Err.missingAuthError
Expand Down Expand Up @@ -235,14 +244,32 @@ createAPITokenHandler (Just tkn) =

deleteTokenHandler :: Text -> Maybe ApiToken -> AppM NoContent
deleteTokenHandler _ Nothing = throw Err.missingAuthError
deleteTokenHandler tokenId (Just tkn) = do
deleteTokenHandler tknId (Just tkn) = do
dbPool <- asks pool
res <- try $ liftIO $ Db.deleteApiToken dbPool tkn tokenId
res <- try $ liftIO $ Db.deleteApiToken dbPool tkn tknId

_ <- either Err.logError pure res

return NoContent

updateTokenHandler :: Maybe ApiToken -> TokenMetadata -> AppM NoContent
updateTokenHandler Nothing _ = throw Err.missingAuthError
updateTokenHandler (Just apiTkn) metadata = do
dbPool <- asks pool

userRes <- try $ liftIO $ Db.getUser dbPool apiTkn

user <- either Err.logError pure userRes

case user of
Nothing -> throw Err.invalidTokenError
Just user' -> do
res <- try $ liftIO $ Db.updateTokenMetadata dbPool user' metadata

_ <- either Err.logError pure res

return NoContent

server settings =
loginHandler
:<|> refreshTokenHandler
Expand All @@ -251,3 +278,4 @@ server settings =
:<|> deleteTokenHandler
:<|> logoutHandler
:<|> registerHandler settings
:<|> updateTokenHandler
17 changes: 16 additions & 1 deletion src/Haka/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Haka.Types
ProjectStatRow (..),
TokenData (..),
LeaderboardRow (..),
TokenMetadata (..),
)
where

Expand All @@ -43,7 +44,11 @@ data StoredApiToken = StoredApiToken
{ -- Some characters to identify a token.
tknId :: Text,
-- When the token was used.
lastUsage :: Maybe UTCTime
lastUsage :: Maybe UTCTime,
-- An optional name given to the token.
tknName :: Maybe Text,
-- An optiona description given to the token.
tknDesc :: Maybe Text
}
deriving (Show, Generic)

Expand Down Expand Up @@ -266,3 +271,13 @@ data LeaderboardRow = LeaderboardRow
leadTotalSeconds :: Int64
}
deriving (Eq, Show, Generic)

data TokenMetadata = TokenMetadata
{ tokenName :: Text,
tokenId :: Text
}
deriving (Show, Generic)

instance ToJSON TokenMetadata

instance FromJSON TokenMetadata

0 comments on commit 788773b

Please sign in to comment.