From 1e7a526f569ebce3687c43a907b45fc2e44fab23 Mon Sep 17 00:00:00 2001 From: Jeffrey Armstrong Date: Mon, 9 May 2022 10:13:32 -0400 Subject: Authorization now checked via Gemini. Finally implemented a single player page in Gemini. --- captain/external.f90 | 239 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 183 insertions(+), 56 deletions(-) diff --git a/captain/external.f90 b/captain/external.f90 index 4c700ae..467f1ca 100644 --- a/captain/external.f90 +++ b/captain/external.f90 @@ -191,6 +191,10 @@ contains allocate(character(len=64)::res) res = "None Found" return + else if(req%auth_level < global_permissions%get("access-releases")) then + allocate(character(len=64)::res) + res = "Not Authorized" + return end if directories => get_directories_in_directory(local_path) @@ -258,10 +262,83 @@ contains end function generate_releases_gemini + function generate_one_player_gemini(req) result(res) + use captain_db + use request_utils, only: get_player_status_utf8, build_link + use server_response, only: request + use config, only: global_permissions + implicit none + + type(request), intent(in)::req + character(len=:), pointer::res + character(len=PLAYER_NAME_LENGTH)::player_name, instruction_name + integer::i, pid, istat, n + integer, dimension(8)::values + character(len=64)::dateconvert + character(len=:), pointer::one_link + integer, dimension(:), pointer::instruction_ids + + call req%last_component(player_name) + i = index(player_name, '.gmi') + player_name = player_name(1:i-1) + pid = get_player_id(trim(player_name)) + + n = get_instructions_count(player=pid) + allocate(character(len=(2*n*PLAYER_NAME_LENGTH + 1024)) :: res) + + res = "Status:" + if(is_player_online(pid)) then + res = trim(res)//" Online" + else + res = trim(res)//" Offline" + end if + + ! Last checkin + call get_last_checkin_time(pid, values) + write(dateconvert, '(I4,A1,I0.2,A1,I0.2,3X,I2,A1,I0.2,A1,I0.2)') & + values(1), '-', values(2), '-', values(3), & + values(5), ':', values(6), ':', values(7) + + res = trim(res)//new_line(' ')//'Last Checkin: '//trim(dateconvert) + + ! List of instructions + res = trim(res)//new_line(' ')//new_line(' ')//"### Instructions for "//trim(player_name) + instruction_ids => get_instruction_ids(player=pid) + if(associated(instruction_ids)) then + do i = 1, n + call get_instruction_name(instruction_ids(i), instruction_name) + one_link => build_link("../instructions/"//trim(instruction_name)//".gmi", trim(instruction_name),& + .true., req%token) + res = trim(res)//new_line(' ')//one_link + deallocate(one_link) + end do + deallocate(instruction_ids) + else + res = trim(res)//new_line(' ')//"None Yet" + end if + + if(req%auth_level >= global_permissions%get("modify-players")) then + ! Token assignment + res = trim(res)//new_line(' ')//new_line(' ')//"### Security" + + if(player_has_token_db(trim(player_name))) then + res = trim(res)//new_line(' ')//"Player currently has a token assigned." + else + res = trim(res)//new_line(' ')//"Player is insecure! Please assign a token!" + end if + + one_link => build_link(trim(player_name)//"/assign_token.gmi", "Assign Token", .true., req%token) + + res = trim(res)//new_line(' ')//one_link + end if + + end function generate_one_player_gemini + function generate_players_gemini(req) result(res) use captain_db use request_utils, only: get_player_status_utf8, build_link use server_response, only: request + use config, only: global_permissions implicit none type(request), intent(in)::req @@ -309,12 +386,15 @@ contains deallocate(players) end if - player_link => build_link("/players/add.gmi", "Add Player", .true., req%token) - res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & - new_line(res(1:1))//player_link + if(req%auth_level >= global_permissions%get("add-players")) then + player_link => build_link("/players/add.gmi", "Add Player", .true., req%token) + + res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & + new_line(res(1:1))//player_link - deallocate(player_link) + deallocate(player_link) + end if end function generate_players_gemini @@ -322,6 +402,7 @@ contains use captain_db use server_response use request_utils, only: get_player_status_utf8, render_jobs_links, build_link + use config, only: global_permissions implicit none type(request)::req @@ -376,22 +457,37 @@ contains i = index(req%location, ".gmi", back=.true.) - raw_link => build_link(req%location(1:i-1)//".json", "View Raw", .true., req%token) - res = trim(res)//nl//raw_link - deallocate(raw_link) + if(req%auth_level >= global_permissions%get("view-raw-instructions")) then + raw_link => build_link(req%location(1:i-1)//".json", "View Raw", .true., req%token) + res = trim(res)//nl//raw_link + deallocate(raw_link) + end if if(n_players == 0) then res = trim(res)//nl//nl//"No players currently can run these instructions" - else + else if(req%auth_level >= global_permissions%get("launch-job")) then res = trim(res)//nl//nl//"### Launch Now" do i = 1, n_players - call get_player_name(players(i), player_name) + call get_player_name(players(i), player_name) player_status = get_player_status_utf8(players(i)) launch_link => build_link(trim(req%location)//"?launch="//trim(player_name), & trim(player_status)//" "//trim(player_name), & .true., req%token) + res = trim(res)//nl//launch_link + deallocate(launch_link) + end do + else + res = trim(res)//nl//nl//"### Assigned Players" + do i = 1, n_players + call get_player_name(players(i), player_name) + player_status = get_player_status_utf8(players(i)) + + launch_link => build_link("/players/"//trim(player_name)//".gmi", & + trim(player_status)//" "//trim(player_name), & + .true., req%token) + res = trim(res)//nl//launch_link deallocate(launch_link) end do @@ -405,39 +501,41 @@ contains deallocate(job_link_text) end if - all_players => get_player_names() - if(associated(all_players)) then - res = trim(res)//nl//nl//"### Assign"//nl//"Assign a player to these instructions" - do i = 1, size(all_players) - if(n_players > 0) then - j = get_player_id(all_players(i)) - if(any(j == players)) then - cycle + if(req%auth_level >= global_permissions%get("assign-instructions")) then + all_players => get_player_names() + if(associated(all_players)) then + res = trim(res)//nl//nl//"### Assign"//nl//"Assign a player to these instructions" + do i = 1, size(all_players) + if(n_players > 0) then + j = get_player_id(all_players(i)) + if(any(j == players)) then + cycle + end if end if - end if - - assign_link => build_link(trim(req%location)//"?assign="//trim(all_players(i)), & - trim(all_players(i)), .true., req%token) - - res = trim(res)//nl//assign_link - - deallocate(assign_link) - end do - deallocate(all_players) - end if - - if(n_players > 0) then - res = trim(res)//nl//nl//"### Remove"//nl//"Remove a player from these instructions" - do i = 1, n_players - call get_player_name(players(i), player_name) - - assign_link => build_link(trim(req%location)//"?remove="//trim(player_name), & - trim(player_name), .true., req%token) - - res = trim(res)//nl//assign_link - - deallocate(assign_link) - end do + + assign_link => build_link(trim(req%location)//"?assign="//trim(all_players(i)), & + trim(all_players(i)), .true., req%token) + + res = trim(res)//nl//assign_link + + deallocate(assign_link) + end do + deallocate(all_players) + end if + + if(n_players > 0) then + res = trim(res)//nl//nl//"### Remove"//nl//"Remove a player from these instructions" + do i = 1, n_players + call get_player_name(players(i), player_name) + + assign_link => build_link(trim(req%location)//"?remove="//trim(player_name), & + trim(player_name), .true., req%token) + + res = trim(res)//nl//assign_link + + deallocate(assign_link) + end do + end if end if end function generate_one_instuction_gemini @@ -446,6 +544,7 @@ contains use captain_db use server_response, only: request use request_utils, only: build_link + use config, only: global_permissions implicit none class(request), intent(in)::req @@ -492,13 +591,15 @@ contains end if - instruction_link => build_link("/instructions/scan.gmi", "Scan for Instructions", & - .true., req%token) + if(req%auth_level >= global_permissions%get("scan-instructions")) then + instruction_link => build_link("/instructions/scan.gmi", "Scan for Instructions", & + .true., req%token) - res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & - new_line(res(1:1))//instruction_link - - deallocate(instruction_link) + res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// & + new_line(res(1:1))//instruction_link + + deallocate(instruction_link) + end if end function generate_instructions_gemini @@ -559,14 +660,16 @@ contains class(request), intent(in)::req logical::is_input_required_request - character(64)::first + character(64)::first, last call req%path_component(1, first) + call req%last_component(last) is_input_required_request = .false. if(req%location == "/players/add.gmi" .or. & req%location == "/login.gmi" .or. & - trim(first) == "login") & + trim(first) == "login" .or. & + trim(last) == "assign_token.gmi") & then is_input_required_request = .true. end if @@ -576,24 +679,28 @@ contains function external_input_required_gemini(req) result(resp) use server_response use gemini_codes + use config, only: global_permissions implicit none class(request), intent(in)::req type(response)::resp - character(64)::first + character(64)::first, last call req%path_component(1, first) + call req%last_component(last) resp%code = GEMINI_CODE_INPUT - if(req%location == "/players/add.gmi") then + if(req%location == "/players/add.gmi" .and. req%auth_level >= global_permissions%get("add-players")) then call resp%set_message("Enter name of new player to add") else if(req%location == "/login.gmi") then call resp%set_message("Enter username:") else if(trim(first) == "login") then call resp%set_message("Enter password:") resp%code = GEMINI_CODE_INPUT_PW + else if(trim(last) == "assign_token.gmi") then + call resp%set_message("Enter token for player:") end if end function external_input_required_gemini @@ -605,16 +712,18 @@ contains use m_uuid, only: UUID_LENGTH use logging use gemini_codes + use config, only: global_permissions implicit none class(request), intent(in)::req type(response)::resp - character(64)::first, second + character(PLAYER_NAME_LENGTH)::first, second, last character(len=:), pointer::session call req%path_component(1, first) + call req%last_component(last) - if(req%location == "/players/add.gmi") then + if(req%location == "/players/add.gmi" .and. req%auth_level >= global_permissions%get("add-players")) then call add_player_db(req%query_string) resp%code = GEMINI_CODE_REDIRECT call resp%set_gemini_session_url("/players.gmi", req%token) @@ -652,6 +761,13 @@ contains call resp%set_url("/loginfailed.gmi") end if + else if(trim(last) == "assign_token.gmi" .and. req%auth_level >= global_permissions%get("modify-players")) then + + call req%path_component(2, second) + call update_player_token_db(trim(second), req%query_string) + resp%code = GEMINI_CODE_REDIRECT + call resp%set_url("../"//trim(second)//".gmi") + end if end function external_input_request_gemini @@ -707,6 +823,7 @@ contains use server_response use logging use gemini_codes + use config, only: global_permissions implicit none class(request), intent(inout)::req @@ -714,7 +831,7 @@ contains resp%code = GEMINI_CODE_REDIRECT - if(req%location == "/instructions/scan.gmi") then + if(req%location == "/instructions/scan.gmi" .and. req%auth_level >= global_permissions%get("scan-instructions")) then call scan_instructions_for_db() call resp%set_url("/instructions.gmi") @@ -738,6 +855,7 @@ contains use request_utils, only: get_job_page_title use utilities, only: build_date use gemini_codes + use captain_db, only: PLAYER_NAME_LENGTH implicit none class(request), intent(in)::req @@ -747,6 +865,8 @@ contains character(len=:), pointer::contents character(64)::first, template_name character(128)::job_page_title + character(PLAYER_NAME_LENGTH)::second + integer::i ! Open the base template if(trim(req%location) == "/" .or. trim(req%location) == "/index.gmi") then @@ -785,8 +905,15 @@ contains contents => generate_players_gemini(req) call page%assign('contents', contents) - else if(req%location(1:9) == '/players/') then - + else if(trim(first) == 'players') then + call req%path_component(2, second) + i = index(second, ".gmi") + if(i > 2) then + call page%assign('title', second(1:i-1)) + end if + contents => generate_one_player_gemini(req) + call page%assign('contents', contents) + else if(trim(req%location) == "/about.gmi") then call page%assign('title', 'About') -- cgit v1.2.3