<commit_before>package net.ripe.db.whois.api.whois.rdap;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.net.InetAddresses;
import net.ripe.db.whois.api.whois.ApiResponseHandler;
import net.ripe.db.whois.api.whois.rdap.domain.RdapObject;
import net.ripe.db.whois.common.dao.RpslObjectDao;
import net.ripe.db.whois.common.domain.IpInterval;
import net.ripe.db.whois.common.domain.ResponseObject;
import net.ripe.db.whois.common.domain.attrs.AttributeParseException;
import net.ripe.db.whois.common.domain.attrs.AutNum;
import net.ripe.db.whois.common.domain.attrs.Domain;
import net.ripe.db.whois.common.rpsl.AttributeType;
import net.ripe.db.whois.common.rpsl.ObjectType;
import net.ripe.db.whois.common.rpsl.RpslAttribute;
import net.ripe.db.whois.common.rpsl.RpslObject;
import net.ripe.db.whois.query.domain.QueryCompletionInfo;
import net.ripe.db.whois.query.domain.QueryException;
import net.ripe.db.whois.query.handler.QueryHandler;
import net.ripe.db.whois.query.planner.AbuseCFinder;
import net.ripe.db.whois.query.query.Query;
import net.ripe.db.whois.query.query.QueryFlag;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.InetAddress;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static net.ripe.db.whois.common.rpsl.ObjectType.*;

@ExternallyManagedLifecycle
@Component
@Path("/")
public class WhoisRdapService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WhoisRdapService.class);

    public static final String WHOIS_VARIANT = System.getProperty("whois.variant","");
    public static final String RDAP_PROPERTIES = "classpath:rdap" + (WHOIS_VARIANT.isEmpty() ? "" : "." + WHOIS_VARIANT) + ".properties";

    private static final int STATUS_TOO_MANY_REQUESTS = 429;
    private static final Set<ObjectType> ABUSE_CONTACT_TYPES = Sets.newHashSet(AUT_NUM, INETNUM, INET6NUM);

    private static final Joiner SLASH_JOINER = Joiner.on("/");
    public static final Joiner COMMA_JOINER = Joiner.on(",");

    private final QueryHandler queryHandler;
    private final RpslObjectDao objectDao;
    private final AbuseCFinder abuseCFinder;
    private final String baseUrl;

    @Value("${rdap.port43:whois.ripe.net}")
    private String port43;

    @Autowired
    public WhoisRdapService(final QueryHandler queryHandler, final RpslObjectDao objectDao, final AbuseCFinder abuseCFinder, @Value("${rdap.public.baseurl:}") final String baseUrl) {
        this.queryHandler = queryHandler;
        this.objectDao = objectDao;
        this.abuseCFinder = abuseCFinder;
        this.baseUrl = baseUrl;
    }

    @GET
    @Produces( { RdapJsonProvider.CONTENT_TYPE_RDAP_JSON, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
    @Path("/{objectType}/{key:.*}")
    public Response lookup(@Context final HttpServletRequest request,
                           @Context HttpHeaders httpHeaders,
                           @PathParam("objectType") final String objectType,
                           @PathParam("key") final String key) {

        Response.ResponseBuilder response;
        String selfUrl = SLASH_JOINER.join(getBaseUrl(request), objectType, key);

        final Set<ObjectType> whoisObjectTypes = Sets.newHashSet();
        try {
            switch (objectType.toLowerCase()) {
                case "autnum":
                    validateAutnum("AS" + key);
                    whoisObjectTypes.add(objectExists(request, AUT_NUM, "AS" + key) ? AUT_NUM : AS_BLOCK);
                    break;

                case "domain":
                    validateDomain(key);
                    whoisObjectTypes.add(DOMAIN);
                    break;

                case "ip":
                    validateIp(key);
                    whoisObjectTypes.add(key.contains(":") ? INET6NUM : INETNUM);
                    break;

                case "entity":
                    validateEntity(key);
                    // TODO: [RL] Configuration (property?) for allowed RPSL object types for entity lookups
                    if (key.toUpperCase().startsWith("IRT-")) {
                        whoisObjectTypes.add(IRT);
                    } else if (key.toUpperCase().startsWith("ORG-")) {
                        whoisObjectTypes.add(ORGANISATION);
                    } else {
                        whoisObjectTypes.add(PERSON);
                        whoisObjectTypes.add(ROLE);
                    }
                    break;

                case "nameserver" : break; // Not yet supported
            }

            if (whoisObjectTypes.isEmpty()) {
                throw new WebApplicationException(Response.Status.BAD_REQUEST);
            }

            response = Response.ok(lookupObject(request, whoisObjectTypes, getKey(whoisObjectTypes, key)));

        } catch (WebApplicationException webex) {
            LOGGER.error("RDAP error", webex);
            int statusCode = webex.getResponse().getStatus();
            response = Response.status(statusCode).entity(RdapException.build(Response.Status.fromStatusCode(statusCode), selfUrl));
        } catch (IllegalArgumentException iae) {
            response = Response.status(Response.Status.BAD_REQUEST.getStatusCode()).entity(RdapException.build(Response.Status.BAD_REQUEST, selfUrl));
        } catch (Throwable t) {
            LOGGER.error("RDAP Internal Server error", t);
            // catch Everything
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(RdapException.build(Response.Status.INTERNAL_SERVER_ERROR, selfUrl));
        }
        mapAcceptableMediaType(response, httpHeaders.getAcceptableMediaTypes());
        response.header("Access-Control-Allow-Origin", "*");
        return response.build();
    }

    @GET
    @Produces( { RdapJsonProvider.CONTENT_TYPE_RDAP_JSON, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
    @Path("/help")
    public Response lookupHelp(@Context final HttpServletRequest request, @Context HttpHeaders httpHeaders) {
        final String selfUrl =  getBaseUrl(request) + "/help";
        final Response.ResponseBuilder response = Response.ok().entity(RdapHelp.build(selfUrl));
        mapAcceptableMediaType(response, httpHeaders.getAcceptableMediaTypes());
        return response.build();
    }

    @GET
    @Path("/")
    public Response redirectToDocumentation(@Context final HttpServletRequest request) {
        return Response.status(Response.Status.MOVED_PERMANENTLY).location(URI.create(getBaseUrl(request) + "/help")).build();
    }


    private void validateDomain(final String key) {
        try {
            Domain.parse(key);
        } catch (AttributeParseException e) {
            throw new IllegalArgumentException("Invalid syntax.");
        }
    }

    private void validateIp(final String key) {
        try {
            IpInterval.parse(key);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid syntax.", e);
        }
    }

    private void validateAutnum(final String key) {<commit_msg>add missing cross site header<commit_after>package net.ripe.db.whois.api.whois.rdap;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.net.InetAddresses;
import net.ripe.db.whois.api.whois.ApiResponseHandler;
import net.ripe.db.whois.api.whois.rdap.domain.RdapObject;
import net.ripe.db.whois.common.dao.RpslObjectDao;
import net.ripe.db.whois.common.domain.IpInterval;
import net.ripe.db.whois.common.domain.ResponseObject;
import net.ripe.db.whois.common.domain.attrs.AttributeParseException;
import net.ripe.db.whois.common.domain.attrs.AutNum;
import net.ripe.db.whois.common.domain.attrs.Domain;
import net.ripe.db.whois.common.rpsl.AttributeType;
import net.ripe.db.whois.common.rpsl.ObjectType;
import net.ripe.db.whois.common.rpsl.RpslAttribute;
import net.ripe.db.whois.common.rpsl.RpslObject;
import net.ripe.db.whois.query.domain.QueryCompletionInfo;
import net.ripe.db.whois.query.domain.QueryException;
import net.ripe.db.whois.query.handler.QueryHandler;
import net.ripe.db.whois.query.planner.AbuseCFinder;
import net.ripe.db.whois.query.query.Query;
import net.ripe.db.whois.query.query.QueryFlag;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.InetAddress;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static net.ripe.db.whois.common.rpsl.ObjectType.*;

@ExternallyManagedLifecycle
@Component
@Path("/")
public class WhoisRdapService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WhoisRdapService.class);

    public static final String WHOIS_VARIANT = System.getProperty("whois.variant","");
    public static final String RDAP_PROPERTIES = "classpath:rdap" + (WHOIS_VARIANT.isEmpty() ? "" : "." + WHOIS_VARIANT) + ".properties";

    private static final int STATUS_TOO_MANY_REQUESTS = 429;
    private static final Set<ObjectType> ABUSE_CONTACT_TYPES = Sets.newHashSet(AUT_NUM, INETNUM, INET6NUM);

    private static final Joiner SLASH_JOINER = Joiner.on("/");
    public static final Joiner COMMA_JOINER = Joiner.on(",");

    private final QueryHandler queryHandler;
    private final RpslObjectDao objectDao;
    private final AbuseCFinder abuseCFinder;
    private final String baseUrl;

    @Value("${rdap.port43:whois.ripe.net}")
    private String port43;

    @Autowired
    public WhoisRdapService(final QueryHandler queryHandler, final RpslObjectDao objectDao, final AbuseCFinder abuseCFinder, @Value("${rdap.public.baseurl:}") final String baseUrl) {
        this.queryHandler = queryHandler;
        this.objectDao = objectDao;
        this.abuseCFinder = abuseCFinder;
        this.baseUrl = baseUrl;
    }

    @GET
    @Produces( { RdapJsonProvider.CONTENT_TYPE_RDAP_JSON, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
    @Path("/{objectType}/{key:.*}")
    public Response lookup(@Context final HttpServletRequest request,
                           @Context HttpHeaders httpHeaders,
                           @PathParam("objectType") final String objectType,
                           @PathParam("key") final String key) {

        Response.ResponseBuilder response;
        String selfUrl = SLASH_JOINER.join(getBaseUrl(request), objectType, key);

        final Set<ObjectType> whoisObjectTypes = Sets.newHashSet();
        try {
            switch (objectType.toLowerCase()) {
                case "autnum":
                    validateAutnum("AS" + key);
                    whoisObjectTypes.add(objectExists(request, AUT_NUM, "AS" + key) ? AUT_NUM : AS_BLOCK);
                    break;

                case "domain":
                    validateDomain(key);
                    whoisObjectTypes.add(DOMAIN);
                    break;

                case "ip":
                    validateIp(key);
                    whoisObjectTypes.add(key.contains(":") ? INET6NUM : INETNUM);
                    break;

                case "entity":
                    validateEntity(key);
                    // TODO: [RL] Configuration (property?) for allowed RPSL object types for entity lookups
                    if (key.toUpperCase().startsWith("IRT-")) {
                        whoisObjectTypes.add(IRT);
                    } else if (key.toUpperCase().startsWith("ORG-")) {
                        whoisObjectTypes.add(ORGANISATION);
                    } else {
                        whoisObjectTypes.add(PERSON);
                        whoisObjectTypes.add(ROLE);
                    }
                    break;

                case "nameserver" : break; // Not yet supported
            }

            if (whoisObjectTypes.isEmpty()) {
                throw new WebApplicationException(Response.Status.BAD_REQUEST);
            }

            response = Response.ok(lookupObject(request, whoisObjectTypes, getKey(whoisObjectTypes, key)));

        } catch (WebApplicationException webex) {
            LOGGER.error("RDAP error", webex);
            int statusCode = webex.getResponse().getStatus();
            response = Response.status(statusCode).entity(RdapException.build(Response.Status.fromStatusCode(statusCode), selfUrl));
        } catch (IllegalArgumentException iae) {
            response = Response.status(Response.Status.BAD_REQUEST.getStatusCode()).entity(RdapException.build(Response.Status.BAD_REQUEST, selfUrl));
        } catch (Throwable t) {
            LOGGER.error("RDAP Internal Server error", t);
            // catch Everything
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).entity(RdapException.build(Response.Status.INTERNAL_SERVER_ERROR, selfUrl));
        }
        mapAcceptableMediaType(response, httpHeaders.getAcceptableMediaTypes());
        response.header("Access-Control-Allow-Origin", "*");
        return response.build();
    }

    @GET
    @Produces( { RdapJsonProvider.CONTENT_TYPE_RDAP_JSON, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
    @Path("/help")
    public Response lookupHelp(@Context final HttpServletRequest request, @Context HttpHeaders httpHeaders) {
        final String selfUrl =  getBaseUrl(request) + "/help";
        final Response.ResponseBuilder response = Response.ok().entity(RdapHelp.build(selfUrl));
        mapAcceptableMediaType(response, httpHeaders.getAcceptableMediaTypes());
        response.header("Access-Control-Allow-Origin", "*");
        return response.build();
    }

    @GET
    @Path("/")
    public Response redirectToDocumentation(@Context final HttpServletRequest request) {
        return Response.status(Response.Status.MOVED_PERMANENTLY).location(URI.create(getBaseUrl(request) + "/help")).build();
    }


    private void validateDomain(final String key) {
        try {
            Domain.parse(key);
        } catch (AttributeParseException e) {
            throw new IllegalArgumentException("Invalid syntax.");
        }
    }

    private void validateIp(final String key) {
        try {
            IpInterval.parse(key);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid syntax.", e);
        }
    }

    private void validateAutnum(final String key) {
{'fraction_non_alphanumeric': 0.1090318884857743, 'fraction_numerical': 0.0014002927884921392, 'mean_word_length': 2.972692793931732, 'pattern_counts': {'":': 10, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2373605', 'n_tokens_mistral': 4599, 'n_tokens_neox': 4536, 'n_words': 809}