Search in sources :

Example 1 with NightfallClientException

use of ai.nightfall.scan.model.NightfallClientException in project nightfall-java-sdk by nightfallai.

the class NightfallClient method scanUploadedFile.

/**
 * Triggers a scan of the file identified by the provided <code>fileID</code>. As the underlying file might be
 * arbitrarily large, this scan will be conducted asynchronously. Results from the scan will be delivered to the
 * webhook URL provided in the <code>request</code> payload.
 *
 * @param request contains metadata identifying which file to scan, as well as the configuration that
 *                describes which detectors to use when scanning.
 * @return an acknowledgment that the asynchronous scan has been initiated.
 * @throws NightfallAPIException thrown if a non-2xx status code is returned by the API.
 * @throws NightfallClientException thrown if a I/O error occurs while processing the request
 * @throws NightfallRequestTimeoutException thrown if the request is aborted because read/write timeout is exceeded
 */
private ScanFileResponse scanUploadedFile(ScanFileRequest request, UUID fileID) {
    String path = "/v3/upload/" + fileID.toString() + "/scan";
    byte[] jsonBody;
    try {
        jsonBody = objectMapper.writeValueAsBytes(request);
    } catch (JsonProcessingException e) {
        throw new NightfallClientException("processing scan file request: " + e.getMessage());
    }
    MediaType json = MediaType.parse("application/json");
    return this.issueRequest(path, "POST", json, jsonBody, null, ScanFileResponse.class);
}
Also used : NightfallClientException(ai.nightfall.scan.model.NightfallClientException) MediaType(okhttp3.MediaType) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException)

Example 2 with NightfallClientException

use of ai.nightfall.scan.model.NightfallClientException in project nightfall-java-sdk by nightfallai.

the class NightfallClient method scanFile.

/**
 * A convenience method that abstracts the details of the multi-step file upload and scan process. In other words,
 * calling this method for a given file is equivalent to (1) manually initializing a file upload session,
 * (2) uploading all chunks of the file, (3) completing the upload, and (4) triggering a scan of the file.
 *
 * <p>The maximum allowed <code>contentSizeBytes</code> is dependent on the terms of your current
 * Nightfall usage plan agreement; check the Nightfall dashboard for more details.
 *
 * <p>This method consumes the provided <code>InputStream</code>, but it *does not* close it; closing remains
 * the caller's responsibility.
 *
 * @param request contains configuration describing which detectors to use to scan the file, as well as a webhook
 *                URL for delivering the results of the scan.
 * @param content a stream of the bytes representing the file to upload
 * @param contentSizeBytes the size of the input stream
 * @param timeout the allowed duration for the request; if the execution time exceeds this duration, the request
 *                will be aborted.
 * @return an acknowledgment that the asynchronous scan has been initiated.
 * @throws NightfallAPIException thrown if a non-2xx status code is returned by the API.
 * @throws NightfallClientException thrown if a I/O error occurs while processing the request
 * @throws NightfallRequestTimeoutException thrown if execution time exceeds the provided <code>timeout</code>,
 *      or if an HTTP request is terminated by the client for exceeding read/write timeouts.
 */
public ScanFileResponse scanFile(ScanFileRequest request, InputStream content, long contentSizeBytes, Duration timeout) {
    if (request == null) {
        throw new IllegalArgumentException("request must be non-null");
    } else if (content == null) {
        throw new IllegalArgumentException("content must be non-null");
    }
    Instant deadline = null;
    if (timeout != null) {
        if (timeout.isNegative()) {
            throw new IllegalArgumentException("timeout must be positive");
        }
        deadline = Instant.now().plus(timeout);
    }
    InitializeFileUploadRequest initRequest = new InitializeFileUploadRequest(contentSizeBytes);
    FileUpload upload = this.initializeFileUpload(initRequest);
    AtomicReference<BaseNightfallException> uploadException = new AtomicReference<>();
    boolean uploadSuccess = doChunkedUpload(upload, content, deadline, uploadException);
    if (!uploadSuccess) {
        BaseNightfallException except = uploadException.get();
        if (except != null) {
            throw except;
        }
        throw new NightfallClientException("internal error: failed to upload all chunks of file");
    }
    CompleteFileUploadRequest completeReq = new CompleteFileUploadRequest(upload.getFileID());
    upload = this.completeFileUpload(completeReq);
    return this.scanUploadedFile(request, upload.getFileID());
}
Also used : InitializeFileUploadRequest(ai.nightfall.scan.model.InitializeFileUploadRequest) NightfallClientException(ai.nightfall.scan.model.NightfallClientException) Instant(java.time.Instant) BaseNightfallException(ai.nightfall.scan.model.BaseNightfallException) AtomicReference(java.util.concurrent.atomic.AtomicReference) CompleteFileUploadRequest(ai.nightfall.scan.model.CompleteFileUploadRequest) FileUpload(ai.nightfall.scan.model.FileUpload)

Example 3 with NightfallClientException

use of ai.nightfall.scan.model.NightfallClientException in project nightfall-java-sdk by nightfallai.

the class NightfallClient method scanText.

/**
 * Scans the provided plaintext against the provided detectors, and returns all findings. The response object will
 * contain a list of lists representing the findings. Each index <code>i</code> in the findings array will
 * correspond one-to-one with the input request payload list, so all findings stored in a given sub-list refer to
 * matches that occurred in the <code>i</code>th index of the request payload.
 *
 * @param request the data to scan, along with the configuration describing how to scan the data. The
 *                request payload may not exceed 500KB.
 * @return an object containing the findings from each item in the request payload
 * @throws NightfallAPIException thrown if a non-2xx status code is returned by the API.
 * @throws NightfallClientException thrown if a I/O error occurs while processing the request
 * @throws IllegalArgumentException thrown if <code>request</code> is null
 * @throws NightfallRequestTimeoutException thrown if the request is aborted because the timeout is exceeded
 */
public ScanTextResponse scanText(ScanTextRequest request) {
    if (request == null) {
        throw new IllegalArgumentException("request must be non-null");
    }
    byte[] jsonBody;
    try {
        jsonBody = objectMapper.writeValueAsBytes(request);
    } catch (JsonProcessingException e) {
        throw new NightfallClientException("processing scan request: " + e.getMessage());
    }
    MediaType json = MediaType.parse("application/json");
    return this.issueRequest("/v3/scan", "POST", json, jsonBody, null, ScanTextResponse.class);
}
Also used : NightfallClientException(ai.nightfall.scan.model.NightfallClientException) MediaType(okhttp3.MediaType) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException)

Example 4 with NightfallClientException

use of ai.nightfall.scan.model.NightfallClientException in project nightfall-java-sdk by nightfallai.

the class NightfallClient method initializeFileUpload.

/**
 * Creates a file upload session. If this operation returns successfully, the ID returned as part of the
 * response object shall be used to refer to the file in all subsequent upload and scanning operations.
 *
 * @param request contains metadata describing the requested file upload, such as the file size in bytes.
 * @return an object representing the file upload.
 * @throws NightfallAPIException thrown if a non-2xx status code is returned by the API.
 * @throws NightfallClientException thrown if a I/O error occurs while processing the request
 * @throws NightfallRequestTimeoutException thrown if the request is aborted because read/write timeout is exceeded
 */
private FileUpload initializeFileUpload(InitializeFileUploadRequest request) {
    byte[] jsonBody;
    try {
        jsonBody = objectMapper.writeValueAsBytes(request);
    } catch (JsonProcessingException e) {
        throw new NightfallClientException("processing init-upload request: " + e.getMessage());
    }
    MediaType json = MediaType.parse("application/json");
    return this.issueRequest("/v3/upload", "POST", json, jsonBody, null, FileUpload.class);
}
Also used : NightfallClientException(ai.nightfall.scan.model.NightfallClientException) MediaType(okhttp3.MediaType) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException)

Example 5 with NightfallClientException

use of ai.nightfall.scan.model.NightfallClientException in project nightfall-java-sdk by nightfallai.

the class NightfallClient method issueRequest.

/**
 * Issues an HTTP request to the provided resource. If the request is successful, the response body will be
 * deserialized into an object based on the provided <code>responseClass</code>. If the response indicates a
 * rate limiting error, the request will be retried after a short sleep.
 *
 * @param path the HTTP resource path
 * @param method the HTTP verb
 * @param body the HTTP request body
 * @param headers HTTP headers
 * @param responseClass the class to deserialize results into
 * @return an instance of the <code>responseClass</code>
 * @throws NightfallClientException thrown if an unexpected error occurs while processing the request
 * @throws NightfallAPIException thrown if the API returns a 4xx or 5xx error code
 * @throws NightfallRequestTimeoutException thrown if the request is aborted because read/write timeout is exceeded
 */
private <E> E issueRequest(String path, String method, MediaType mediaType, byte[] body, Headers headers, Class<E> responseClass) {
    String url = this.apiHost + path;
    Request.Builder builder = new Request.Builder().url(url);
    if (headers != null) {
        builder.headers(headers);
    }
    if (this.implVersion != null && !this.implVersion.equals("")) {
        builder.addHeader("User-Agent", "nightfall-java-sdk/" + this.implVersion);
    }
    builder.addHeader("Authorization", "Bearer " + this.apiKey);
    RequestBody reqBody = null;
    if (body != null && body.length > 0) {
        reqBody = RequestBody.create(body, mediaType);
    } else if (!method.equals("GET") && !method.equals("HEAD")) {
        reqBody = RequestBody.create(new byte[0]);
    }
    builder.method(method, reqBody);
    Request request = builder.build();
    Call call = this.httpClient.newCall(request);
    NightfallErrorResponse lastError = null;
    int errorCode = 0;
    for (int attempt = 0; attempt < this.retryCount; attempt++) {
        try (Response response = call.execute()) {
            if (!response.isSuccessful()) {
                try {
                    lastError = objectMapper.readValue(response.body().bytes(), NightfallErrorResponse.class);
                } catch (Throwable t) {
                // best effort to get more info, swallow failure
                }
                if (response.code() == 429 && attempt < this.retryCount - 1) {
                    Thread.sleep(1000);
                    // cannot re-use the same call object
                    call = call.clone();
                    continue;
                }
                // cannot directly throw exception here because of Throwable catch branch; need to break
                errorCode = response.code();
                break;
            }
            if (Void.class.equals(responseClass)) {
                return null;
            }
            return objectMapper.readValue(response.body().bytes(), responseClass);
        } catch (IOException e) {
            // If OkHTTP times out, allow retries
            if (e.getMessage().equalsIgnoreCase("timeout") || e.getMessage().equalsIgnoreCase("read timed out")) {
                if (attempt >= this.retryCount - 1) {
                    throw new NightfallRequestTimeoutException("request timed out");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ee) {
                // swallow
                }
                // cannot re-use the same call object
                call = call.clone();
                continue;
            }
            throw new NightfallClientException("issuing HTTP request: " + e.getMessage());
        } catch (Throwable t) {
            throw new NightfallClientException("failure executing HTTP request: " + t.getMessage());
        }
    }
    if (errorCode > 0) {
        throw new NightfallAPIException("unsuccessful response", lastError, errorCode);
    }
    String message = "exceeded max retry count on request: " + path;
    throw new NightfallAPIException(message, lastError, 429);
}
Also used : Call(okhttp3.Call) NightfallClientException(ai.nightfall.scan.model.NightfallClientException) NightfallRequestTimeoutException(ai.nightfall.scan.model.NightfallRequestTimeoutException) InitializeFileUploadRequest(ai.nightfall.scan.model.InitializeFileUploadRequest) ScanFileRequest(ai.nightfall.scan.model.ScanFileRequest) Request(okhttp3.Request) ScanTextRequest(ai.nightfall.scan.model.ScanTextRequest) UploadFileChunkRequest(ai.nightfall.scan.model.UploadFileChunkRequest) CompleteFileUploadRequest(ai.nightfall.scan.model.CompleteFileUploadRequest) IOException(java.io.IOException) NightfallAPIException(ai.nightfall.scan.model.NightfallAPIException) ScanTextResponse(ai.nightfall.scan.model.ScanTextResponse) NightfallErrorResponse(ai.nightfall.scan.model.NightfallErrorResponse) Response(okhttp3.Response) ScanFileResponse(ai.nightfall.scan.model.ScanFileResponse) NightfallErrorResponse(ai.nightfall.scan.model.NightfallErrorResponse) RequestBody(okhttp3.RequestBody)

Aggregations

NightfallClientException (ai.nightfall.scan.model.NightfallClientException)6 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)3 MediaType (okhttp3.MediaType)3 BaseNightfallException (ai.nightfall.scan.model.BaseNightfallException)2 CompleteFileUploadRequest (ai.nightfall.scan.model.CompleteFileUploadRequest)2 InitializeFileUploadRequest (ai.nightfall.scan.model.InitializeFileUploadRequest)2 UploadFileChunkRequest (ai.nightfall.scan.model.UploadFileChunkRequest)2 IOException (java.io.IOException)2 FileUpload (ai.nightfall.scan.model.FileUpload)1 NightfallAPIException (ai.nightfall.scan.model.NightfallAPIException)1 NightfallErrorResponse (ai.nightfall.scan.model.NightfallErrorResponse)1 NightfallRequestTimeoutException (ai.nightfall.scan.model.NightfallRequestTimeoutException)1 ScanFileRequest (ai.nightfall.scan.model.ScanFileRequest)1 ScanFileResponse (ai.nightfall.scan.model.ScanFileResponse)1 ScanTextRequest (ai.nightfall.scan.model.ScanTextRequest)1 ScanTextResponse (ai.nightfall.scan.model.ScanTextResponse)1 Instant (java.time.Instant)1 Semaphore (java.util.concurrent.Semaphore)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1