package com.hithomelabs.cftunnels.Controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.hithomelabs.cftunnels.Config.AuthoritiesToGroupMapping;
import com.hithomelabs.cftunnels.Config.CloudflareConfig;
import com.hithomelabs.common.config.RestTemplateConfig;
import com.hithomelabs.cftunnels.Entity.Request;
import com.hithomelabs.cftunnels.Entity.Tunnel;
import com.hithomelabs.cftunnels.Entity.User;
import com.hithomelabs.cftunnels.Headers.AuthKeyEmailHeader;
import com.hithomelabs.cftunnels.Models.Config;
import com.hithomelabs.cftunnels.Models.Ingress;
import com.hithomelabs.cftunnels.Models.TunnelResponse;
import com.hithomelabs.cftunnels.Models.TunnelsResponse;
import com.hithomelabs.cftunnels.Repositories.UserRepository;
import com.hithomelabs.cftunnels.Services.CloudflareAPIService;
import com.hithomelabs.cftunnels.Services.MappingRequestService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.dao.DataAccessException;
import org.springframework.http.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
/**
* REST Controller for managing Cloudflare Tunnels.
*
*
This controller provides the public API for managing Cloudflare Tunnels
* and their ingress mappings. All endpoints require authentication via OIDC
* and are protected by role-based access control.
*
* Base URL: {@code /cloudflare}
*
* Authentication: OIDC-based with role-based access
*
* Available Roles:
*
* - USER - View tunnels and requests
* - DEVELOPER - Create/modify/delete mappings
* - APPROVER - Approve/reject requests
* - ADMIN - Full tunnel configuration access
*
*
* Example Usage:
*
* # Get all tunnels (requires USER role)
* curl -H "Authorization: Bearer <token>" \
* https://api.example.com/cloudflare/tunnels
*
* # Add a mapping (requires ADMIN role)
* curl -X POST -H "Authorization: Bearer <token>" \
* -H "Content-Type: application/json" \
* -d '{"hostname":"api.example.com","service":"http://localhost:8080"}' \
* https://api.example.com/cloudflare/tunnels/{tunnelId}/mappings
*
*
* @see CloudflareAPIService
* @see MappingRequestService
*/
@RestController
@RequestMapping("/cloudflare")
public class TunnelController implements ErrorController {
private final RestTemplate restTemplate = new RestTemplate();
private static final String ERROR_PATH = "/error";
@Autowired
private AuthoritiesToGroupMapping authoritiesToGroupMapping;
@Autowired
private CloudflareConfig cloudflareConfig;
@Autowired
private AuthKeyEmailHeader authKeyEmailHeader;
@Autowired
private RestTemplateConfig restTemplateConfig;
@Autowired
CloudflareAPIService cloudflareAPIService;
@Autowired
MappingRequestService mappingRequestService;
@Autowired
private UserRepository userRepository;
/**
* Current environment (loaded from spring.profiles.active).
*/
@Value("${spring.profiles.active}")
private String environment;
/**
* Get current user information.
*
* Returns the authenticated user's username and roles.
*
* @param oidcUser The authenticated OIDC user
* @return Map containing username and roles
* @throws SecurityException if authentication fails
*/
@PreAuthorize("hasAnyRole('USER')")
@GetMapping("/whoami")
public Map whoAmI(@AuthenticationPrincipal OidcUser oidcUser) {
List authorities = oidcUser.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList();
return Map.of(
"username", oidcUser.getPreferredUsername(),
"roles", authorities
);
}
/**
* Get all tunnels from Cloudflare API.
*
* Fetches the complete list of tunnels from Cloudflare,
* including their status and configuration from the Cloudflare API.
*
* @return Map containing list of all tunnels
* @throws SecurityException if user lacks required role
* @see Cloudflare API
*/
@PreAuthorize("hasAnyRole('USER')")
@GetMapping("/tunnels")
@Operation( security = { @SecurityRequirement(name = "oidcAuth") } )
public ResponseEntity