package com.hithomelabs.cftunnels.Services; import com.hithomelabs.cftunnels.Entity.Mapping; import com.hithomelabs.cftunnels.Entity.Protocol; import com.hithomelabs.cftunnels.Entity.Request; import com.hithomelabs.cftunnels.Entity.Tunnel; import com.hithomelabs.cftunnels.Entity.User; import com.hithomelabs.cftunnels.Models.Ingress; import com.hithomelabs.cftunnels.Repositories.MappingRepository; import com.hithomelabs.cftunnels.Repositories.RequestRepository; import com.hithomelabs.cftunnels.Repositories.TunnelRepository; import com.hithomelabs.cftunnels.Repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.UUID; @Service public class MappingRequestService { @Autowired UserRepository userRepository; @Autowired MappingRepository mappingRepository; @Autowired RequestRepository requestRepository; @Autowired TunnelRepository tunnelRepository; @Autowired CloudflareAPIService cloudflareAPIService; public Mapping createMapping(UUID tunnelId, Ingress ingress){ Tunnel tunnel = tunnelRepository.findById(tunnelId).orElseThrow(() -> new RuntimeException("Tunnel not found")); Mapping mapping = createMappingFromTunnelIngress(tunnel, ingress); return mappingRepository.save(mapping); } public Request createRequest(Mapping mapping, User user){ Request request = new Request(); request.setMapping(mapping); request.setCreatedBy(user); request.setStatus(Request.RequestStatus.PENDING); return requestRepository.save(request); } public Request createMappingRequest(String tunnelId, Ingress ingress, OidcUser oidcUser){ User user = userRepository.findByEmail(oidcUser.getEmail()).orElseGet(()-> mapUser(oidcUser)); Mapping mapping = createMapping(UUID.fromString(tunnelId), ingress); return createRequest(mapping, user); } @Transactional(readOnly = true) public List getAllRequests() { return requestRepository.findAllWithDetails(); } public User mapUser(OidcUser oidcUser){ String email = oidcUser.getEmail(); String name = oidcUser.getNickName(); User user = new User(); user.setEmail(email); user.setName(name); userRepository.save(user); return user; } public Mapping createMappingFromTunnelIngress(Tunnel tunnel, Ingress ingress){ Mapping mapping = new Mapping(); mapping.setTunnel(tunnel); String serviceString = ingress.getService().toLowerCase(); Protocol protocol = parseProtocol(serviceString); mapping.setProtocol(protocol); mapping.setPort(Integer.parseInt(ingress.getService().split(":")[2])); mapping.setSubdomain(ingress.getHostname().split("\\.")[0]); return mapping; } private Protocol parseProtocol(String serviceString) { if (serviceString.startsWith("https://")) { return Protocol.HTTPS; } else if (serviceString.startsWith("tcp://")) { return Protocol.TCP; } else if (serviceString.startsWith("ssh://")) { return Protocol.SSH; } return Protocol.HTTP; } @Transactional public Request approveRequest(UUID requestId, User approver) { Request request = requestRepository.findByIdWithDetails(requestId) .orElseThrow(() -> new NoSuchElementException("Request not found")); if (request.getStatus() != Request.RequestStatus.PENDING) { throw new IllegalStateException("Request is not in PENDING status"); } Mapping mapping = request.getMapping(); Tunnel tunnel = mapping.getTunnel(); Ingress ingress = createIngressFromMapping(mapping); ResponseEntity response = cloudflareAPIService.addTunnelIngress( tunnel.getId().toString(), ingress ); if (!response.getStatusCode().is2xxSuccessful()) { throw new RuntimeException("Failed to add mapping to Cloudflare"); } request.setStatus(Request.RequestStatus.APPROVED); request.setAcceptedBy(approver); return requestRepository.save(request); } @Transactional public Request rejectRequest(UUID requestId, User rejecter) { Request request = requestRepository.findByIdWithDetails(requestId) .orElseThrow(() -> new NoSuchElementException("Request not found")); if (request.getStatus() != Request.RequestStatus.PENDING) { throw new IllegalStateException("Request is not in PENDING status"); } request.setStatus(Request.RequestStatus.REJECTED); request.setAcceptedBy(rejecter); return requestRepository.save(request); } private static final String SERVER_IP = "192.168.0.100"; private Ingress createIngressFromMapping(Mapping mapping) { Tunnel tunnel = mapping.getTunnel(); String protocol = mapping.getProtocol().name().toLowerCase(); String service = protocol + "://" + SERVER_IP + ":" + mapping.getPort(); String hostname = mapping.getSubdomain() + ".hithomelabs.com"; return new Ingress(service, hostname, null, null); } }