From 8160fd02d666dd128e0defaee268a25c0d08798b Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 11:55:42 +0200 Subject: [PATCH 1/8] Add calendar endpoint for PATs Changelog: added --- app/controllers/concerns/render_access_tokens.rb | 16 ++++++++++++++++ .../personal_access_tokens_controller.rb | 10 ++++++++++ app/helpers/feed_token_helper.rb | 7 ++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/render_access_tokens.rb b/app/controllers/concerns/render_access_tokens.rb index 43e4686e66f993..677a996b987035 100644 --- a/app/controllers/concerns/render_access_tokens.rb +++ b/app/controllers/concerns/render_access_tokens.rb @@ -29,4 +29,20 @@ def add_pagination_headers(relation) def page (params[:page] || 1).to_i end + + def expiry_ics(tokens) + cal = Icalendar::Calendar.new + tokens.each do |token| + cal.event do |event| + event.dtstart = Icalendar::Values::Date.new(token[:expires_at].delete('-')) + event.dtend = Icalendar::Values::Date.new(token[:expires_at].delete('-')) + event.summary = "Token #{token[:name]} expires today" + end + end + cal.to_ical + end + + def expiry_ics_url + url_for({ feed_token: generate_feed_token(:ics) }) + end end diff --git a/app/controllers/user_settings/personal_access_tokens_controller.rb b/app/controllers/user_settings/personal_access_tokens_controller.rb index 0bb71966b2141d..de1a33647fa38b 100644 --- a/app/controllers/user_settings/personal_access_tokens_controller.rb +++ b/app/controllers/user_settings/personal_access_tokens_controller.rb @@ -3,10 +3,12 @@ module UserSettings class PersonalAccessTokensController < ApplicationController include RenderAccessTokens + include FeedTokenHelper feature_category :system_access before_action :check_personal_access_tokens_enabled + prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:ics) } def index set_index_vars @@ -21,6 +23,14 @@ def index format.json do render json: @active_access_tokens end + format.ics do + if params[:feed_token] + response.headers['Content-Type'] = 'text/plain' + render plain: expiry_ics(@active_access_tokens) + else + redirect_to "#{request.path}?feed_token=#{generate_feed_token_with_path(:ics, request.path)}" + end + end end end diff --git a/app/helpers/feed_token_helper.rb b/app/helpers/feed_token_helper.rb index 751a8df4782ac2..0a44d6c5ee32ae 100644 --- a/app/helpers/feed_token_helper.rb +++ b/app/helpers/feed_token_helper.rb @@ -2,10 +2,15 @@ module FeedTokenHelper def generate_feed_token(type) + generate_feed_token_with_path(type, current_request.path) + end + + def generate_feed_token_with_path(type, path) feed_token = current_user&.feed_token return unless feed_token - final_path = "#{current_request.path}.#{type}" + final_path = path + final_path += ".#{type}" unless path.ends_with?(".#{type}") digest = OpenSSL::HMAC.hexdigest("SHA256", feed_token, final_path) "#{User::FEED_TOKEN_PREFIX}#{digest}-#{current_user.id}" end -- GitLab From 9db0c1ee3db735d417e112089536bfa1491f9f16 Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 10:04:02 +0000 Subject: [PATCH 2/8] Remove not needed method --- app/controllers/concerns/render_access_tokens.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/concerns/render_access_tokens.rb b/app/controllers/concerns/render_access_tokens.rb index 677a996b987035..5e4c31b0ba751d 100644 --- a/app/controllers/concerns/render_access_tokens.rb +++ b/app/controllers/concerns/render_access_tokens.rb @@ -41,8 +41,4 @@ def expiry_ics(tokens) end cal.to_ical end - - def expiry_ics_url - url_for({ feed_token: generate_feed_token(:ics) }) - end end -- GitLab From 1096a422567ba09b13ce38d08f97e5f9e6d747d1 Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 12:39:24 +0200 Subject: [PATCH 3/8] Add spec --- .../user_settings/personal_access_tokens_controller_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb index b1d6fc6f479d9e..f8dd8f6a267cb6 100644 --- a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb @@ -106,6 +106,12 @@ def created_token expect(json_response.count).to eq(1) end + it 'returns redirect for ics format' do + get :index, params: { format: :ics } + + expect(response).to have_gitlab_http_status(:found) + end + it 'sets available scopes' do expect(assigns(:scopes)).to eq(Gitlab::Auth.available_scopes_for(access_token_user)) end -- GitLab From 9efa8de34e4d197ab1a0b18bf429d45e6ef5fc49 Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 13:04:02 +0200 Subject: [PATCH 4/8] Add documentation for PAT expiry calendar --- doc/user/profile/personal_access_tokens.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md index 7969b1cf318ab2..141a4c89ecc327 100644 --- a/doc/user/profile/personal_access_tokens.md +++ b/doc/user/profile/personal_access_tokens.md @@ -180,6 +180,10 @@ Personal access tokens expire on the date you define, at midnight, 00:00 AM UTC. [maximum allowed lifetime for the token](../../administration/settings/account_and_limit_settings.md#limit-the-lifetime-of-access-tokens). If the maximum allowed lifetime is not set, the default expiry date is 365 days from the date of creation. +### Personal access token expiry calendar + +You can subscribe to an iCalendar endpoint which contains events at the expiry date for each token. This endpoint is available after login at `/-/user_settings/personal_access_tokens.ics` + ### Create a service account personal access token with no expiry date You can [create a personal access token for a service account](../../api/groups.md#create-personal-access-token-for-service-account-user) with no expiry date. These personal access tokens never expire, unlike non-service account personal access tokens. -- GitLab From b483c9ceb9c410e3197955adb9e073daadec7d40 Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 13:21:43 +0000 Subject: [PATCH 5/8] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Jon Glassman --- doc/user/profile/personal_access_tokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md index 141a4c89ecc327..9cec59b2c0056b 100644 --- a/doc/user/profile/personal_access_tokens.md +++ b/doc/user/profile/personal_access_tokens.md @@ -182,7 +182,7 @@ Personal access tokens expire on the date you define, at midnight, 00:00 AM UTC. ### Personal access token expiry calendar -You can subscribe to an iCalendar endpoint which contains events at the expiry date for each token. This endpoint is available after login at `/-/user_settings/personal_access_tokens.ics` +You can subscribe to an iCalendar endpoint which contains events at the expiry date for each token. After signing in, this endpoint is available at `/-/user_settings/personal_access_tokens.ics`. ### Create a service account personal access token with no expiry date -- GitLab From 6d438b9e51b41f3254351dcdb58fb6523e8e94fa Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 13:58:44 +0000 Subject: [PATCH 6/8] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Bishwa Hang Rai --- .../user_settings/personal_access_tokens_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb index f8dd8f6a267cb6..bb64c16bbd4680 100644 --- a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb @@ -109,7 +109,7 @@ def created_token it 'returns redirect for ics format' do get :index, params: { format: :ics } - expect(response).to have_gitlab_http_status(:found) + expect(response).to redirect_to(%r{/-/user_settings/personal_access_tokens\?feed_token=}) end it 'sets available scopes' do -- GitLab From 823b24479b948423688a7f5e3eddbe5fe6451ce1 Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 16:17:02 +0200 Subject: [PATCH 7/8] Add spec for actual calendar content --- .../personal_access_tokens_controller_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb index bb64c16bbd4680..1ed6f4d69a27fa 100644 --- a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb @@ -112,6 +112,16 @@ def created_token expect(response).to redirect_to(%r{/-/user_settings/personal_access_tokens\?feed_token=}) end + it 'returns an iCalendar after redirect' do + get :index, params: { format: :ics } + + expect(response).to redirect_to(%r{/-/user_settings/personal_access_tokens\?feed_token=}) + + get :index, params: { format: :ics, feed_token: response.location.split('=').last } + + expect(response.body).to include('BEGIN:VCALENDAR') + end + it 'sets available scopes' do expect(assigns(:scopes)).to eq(Gitlab::Auth.available_scopes_for(access_token_user)) end -- GitLab From 43b310757b93289242c36a3acfd069d9bec70e1d Mon Sep 17 00:00:00 2001 From: Joern Schneeweisz Date: Wed, 15 May 2024 16:21:53 +0200 Subject: [PATCH 8/8] Simplify spec for actual calendar content --- .../personal_access_tokens_controller_spec.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb index 1ed6f4d69a27fa..0487c1f2e2f23f 100644 --- a/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/user_settings/personal_access_tokens_controller_spec.rb @@ -106,13 +106,7 @@ def created_token expect(json_response.count).to eq(1) end - it 'returns redirect for ics format' do - get :index, params: { format: :ics } - - expect(response).to redirect_to(%r{/-/user_settings/personal_access_tokens\?feed_token=}) - end - - it 'returns an iCalendar after redirect' do + it 'returns an iCalendar after redirect for ics format' do get :index, params: { format: :ics } expect(response).to redirect_to(%r{/-/user_settings/personal_access_tokens\?feed_token=}) -- GitLab