From 19b91f1d5c958b8a1eea377a95bd037ed96edcac Mon Sep 17 00:00:00 2001
From: zachmann <gabriel.zachmann@kit.edu>
Date: Mon, 5 Dec 2022 17:12:17 +0100
Subject: [PATCH] improve handling of expired mytokens

---
 CHANGELOG.md                                 | 10 +++++
 go.mod                                       |  2 +-
 go.sum                                       |  2 +
 internal/db/dbmigrate/scripts/v0.7.0.pre.sql | 45 ++++++++++++++++++++
 internal/db/dbrepo/mytokenrepo/tree/tree.go  |  1 +
 internal/server/web/static/js/tokeninfo.js   | 13 ++++--
 6 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2ec307a..c216a5e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,9 +14,19 @@
 
 ## mytoken 0.7.0
 
+### Features
+
+- Webinterface has option to show event history for other mytokens in mytoken list.
+
 ### Enhancements
 
 - Improved responsiveness of webinterface
+- Expired mytokens are now greyed-out in webinterface mytoken list
+- The database auto-cleanup now only removes mytokens expired more than a month ago.
+  - This allows expired tokens to be shown in a mytoken list for extended periods.
+  - This also allows to obtain history for expired tokens (by using a mytoken with the `manage_mytokens:list`
+    capability) for a longer time.
+  - Mytokens are still directly deleted when revoked.
 
 ### API
 
diff --git a/go.mod b/go.mod
index 314dfa14..44d84c1d 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/jinzhu/copier v0.3.5
 	github.com/jmoiron/sqlx v1.3.5
 	github.com/lestrrat-go/jwx v1.2.25
-	github.com/oidc-mytoken/api v0.9.2-0.20221125114557-91c7bae719ca
+	github.com/oidc-mytoken/api v0.9.2-0.20221205154634-0c914eb8569d
 	github.com/oidc-mytoken/lib v0.6.2-0.20221125141521-dae7f2a63fc2
 	github.com/oidc-mytoken/utils v0.1.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
diff --git a/go.sum b/go.sum
index 65e0ae8c..aca02174 100644
--- a/go.sum
+++ b/go.sum
@@ -373,6 +373,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/oidc-mytoken/api v0.9.1/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE=
 github.com/oidc-mytoken/api v0.9.2-0.20221125114557-91c7bae719ca h1:Az8gcUKX98Yh48RSxMHEioy0KdJaOvJVCpTtW+tcLR8=
 github.com/oidc-mytoken/api v0.9.2-0.20221125114557-91c7bae719ca/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE=
+github.com/oidc-mytoken/api v0.9.2-0.20221205154634-0c914eb8569d h1:cAP+SXYJMkiwJhWpj4YCjL5OuJ8+OMaxRW8eDdBh1Cg=
+github.com/oidc-mytoken/api v0.9.2-0.20221205154634-0c914eb8569d/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE=
 github.com/oidc-mytoken/lib v0.6.2-0.20221125141521-dae7f2a63fc2 h1:ygQMfCtOGnZxsW7cAhBZCSfGgg3qcfvPVkc2Wq+0L4A=
 github.com/oidc-mytoken/lib v0.6.2-0.20221125141521-dae7f2a63fc2/go.mod h1:U0mC1zWdWKYPekoNTYSQZB5SHFk4fPz+JhfPgWs4TTs=
 github.com/oidc-mytoken/utils v0.1.0 h1:Ia60CYjVzs4X35twdAB1NTXDyYjxe/IWDI/MkcvQHnc=
diff --git a/internal/db/dbmigrate/scripts/v0.7.0.pre.sql b/internal/db/dbmigrate/scripts/v0.7.0.pre.sql
index df3d342c..633e1c61 100644
--- a/internal/db/dbmigrate/scripts/v0.7.0.pre.sql
+++ b/internal/db/dbmigrate/scripts/v0.7.0.pre.sql
@@ -37,5 +37,50 @@ BEGIN
     DROP TABLE effected_MTIDs;
 END;;
 
+CREATE OR REPLACE PROCEDURE Cleanup_MTokens()
+BEGIN
+    DELETE FROM MTokens WHERE DATE_ADD(expires_at, INTERVAL 1 MONTH) < CURRENT_TIMESTAMP();
+END;;
+
+CREATE OR REPLACE PROCEDURE Cleanup_ProxyTokens()
+BEGIN
+    DELETE
+        FROM ProxyTokens
+        WHERE id IN (SELECT id
+                         FROM TransferCodesAttributes
+                         WHERE DATE_ADD(expires_at, INTERVAL 1 MONTH) < CURRENT_TIMESTAMP());
+END;;
+
+CREATE OR REPLACE PROCEDURE MTokens_GetForUser(IN UID BIGINT UNSIGNED)
+BEGIN
+    SELECT id, parent_id, id AS mom_id, name, created, expires_at, ip_created AS ip
+        FROM MTokens
+        WHERE user_id = UID
+        ORDER BY created;
+END;
+
+CREATE OR REPLACE PROCEDURE MTokens_GetSubtokens(IN MTID VARCHAR(128))
+BEGIN
+    CREATE TEMPORARY TABLE IF NOT EXISTS effected_MTIDs (id VARCHAR(128));
+    TRUNCATE effected_MTIDs;
+    INSERT INTO effected_MTIDs
+    WITH RECURSIVE childs AS (SELECT id, parent_id
+                                  FROM MTokens
+                                  WHERE id = MTID
+                              UNION ALL
+                              SELECT mt.id, mt.parent_id
+                                  FROM MTokens mt
+                                           INNER JOIN childs c
+                                  WHERE mt.parent_id = c.id)
+    SELECT id
+        FROM childs;
+    SELECT m.id, m.parent_id, m.id AS mom_id, m.name, m.created, m.expires_at, m.ip_created AS ip
+        FROM MTokens m
+        WHERE m.id IN
+              (SELECT id
+                   FROM effected_MTIDs);
+    DROP TABLE effected_MTIDs;
+END;
+
 DELIMITER ;
 
diff --git a/internal/db/dbrepo/mytokenrepo/tree/tree.go b/internal/db/dbrepo/mytokenrepo/tree/tree.go
index c2e5c323..de3ce279 100644
--- a/internal/db/dbrepo/mytokenrepo/tree/tree.go
+++ b/internal/db/dbrepo/mytokenrepo/tree/tree.go
@@ -20,6 +20,7 @@ type MytokenEntry struct {
 	ParentID         mtid.MTID         `db:"parent_id" json:"-"`
 	Name             db.NullString     `json:"name,omitempty"`
 	CreatedAt        unixtime.UnixTime `db:"created" json:"created"`
+	ExpiresAt        unixtime.UnixTime `db:"expires_at" json:"expires_at,omitempty"`
 	MOMID            string            `db:"mom_id" json:"mom_id"`
 }
 
diff --git a/internal/server/web/static/js/tokeninfo.js b/internal/server/web/static/js/tokeninfo.js
index cc644008..eb8250e2 100644
--- a/internal/server/web/static/js/tokeninfo.js
+++ b/internal/server/web/static/js/tokeninfo.js
@@ -129,7 +129,9 @@ function _tokenTreeToHTML(tree, deleteClass, depth, parentID = 0) {
     let name = token['name'] || 'unnamed token';
     let nameClass = name === 'unnamed token' ? ' text-muted' : '';
     let thisID = `token-tree-el-${tokenTreeIDCounter++}`
-    let time = formatTime(token['created']);
+    let created = formatTime(token['created']);
+    let expires_at = token['expires_at'] || 0;
+    let expires = expires_at === 0 ? `<span class="text-muted">Does not expire</span>` : formatTime(expires_at);
     let tableEntries = "";
     let children = tree['children'];
     let hasChildren = false;
@@ -141,7 +143,11 @@ function _tokenTreeToHTML(tree, deleteClass, depth, parentID = 0) {
     }
     let historyBtn = `<button id="history-${token['mom_id']}" class="btn ml-2" type="button" onclick="showHistoryForID.call(this)" ${loggedIn ? "" : "disabled"} data-toggle="tooltip" data-placement="right" title="${loggedIn ? 'Event History' : 'Sign in to show event history.'}"><i class="fas fa-history"></i></button>`;
     let deleteBtn = `<button id="revoke-${token['mom_id']}" class="btn ${deleteClass}" type="button" onclick="startRevocateID.call(this)" ${loggedIn ? "" : "disabled"} data-toggle="tooltip" data-placement="right" title="${loggedIn ? 'Revoke Token' : 'Sign in to revoke token.'}"><i class="fas fa-trash"></i></button>`;
-    tableEntries = `<tr id="${thisID}" parent-id="${parentID}" class="${depth > 0 ? 'd-none' : ''}"><td class="${hasChildren ? 'token-fold' : ''}${nameClass}"><span style="margin-right: ${1.5 * depth}rem;"></span><i class="mr-2 fas fa-caret-right${hasChildren ? "" : " d-none"}"></i>${name}</td><td>${time}</td><td>${token['ip']}</td><td>${historyBtn}${deleteBtn}</td></tr>` + tableEntries;
+    let tr_class = depth > 0 ? 'd-none' : '';
+    if (expires_at !== 0 && new Date(expires_at * 1000) < new Date()) {
+        tr_class += " text-muted";
+    }
+    tableEntries = `<tr id="${thisID}" parent-id="${parentID}" class="${tr_class}"><td class="${hasChildren ? 'token-fold' : ''}${nameClass}"><span style="margin-right: ${1.5 * depth}rem;"></span><i class="mr-2 fas fa-caret-right${hasChildren ? "" : " d-none"}"></i>${name}</td><td>${created}</td><td>${token['ip']}</td><td>${expires}</td><td>${historyBtn}${deleteBtn}</td></tr>` + tableEntries;
     return tableEntries
 }
 
@@ -155,9 +161,10 @@ function tokenlistToHTML(tokenTrees, deleteClass) {
     }
     return '<table class="table table-hover table-grey">' +
         '<thead><tr>' +
-        '<th style="min-width: 50%;">Token Name</th>' +
+        '<th style="min-width: 40%;">Token Name</th>' +
         '<th>Created</th>' +
         '<th>Created from IP</th>' +
+        '<th>Expires</th>' +
         '<th></th>' +
         '</tr></thead>' +
         '<tbody>' +
-- 
GitLab