# # The MIT License(MIT) # # Copyright(c) 2016 Copyleaks LTD (https://copyleaks.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # = require 'net/http' require 'json' require 'date' module Copyleaks class API def initialize # copyleaks identity http client _identity_server_uri = URI.parse(Config.identity_server_uri) @id_client = Net::HTTP.new(_identity_server_uri.host, _identity_server_uri.port) @id_client.use_ssl = true # copyleaks api http client _api_server_uri = URI.parse(Config.api_server_uri) @api_client = Net::HTTP.new(_api_server_uri.host, _api_server_uri.port) @api_client.use_ssl = true end # Login to Copyleaks authentication server. # For more info: https://api.copyleaks.com/documentation/v3/account/login. # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. We recommend to implement exponential backoff algorithm as described here: https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [String] email Copyleaks account email address. # @param [String] key Copyleaks account secret key. # @return A authentication token that being expired after certain amount of time. def login(email, key) raise 'email is Invalid, must be instance of String' if email.nil? || !email.instance_of?(String) raise 'key is Invalid, must be instance of String' if key.nil? || !email.instance_of?(String) path = '/v3/account/login/api' headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent } payload = { email: email, key: key } request = Net::HTTP::Post.new(path, headers) request.body = payload.to_json res_data = handle_response(@id_client.request(request), 'login') CopyleaksAuthToken.new(res_data['.expires'], res_data['access_token'], res_data['.issued']) end # Verify that Copyleaks authentication token is exists and not exipired. # * Exceptions: # * * AuthExipredException: authentication expired. Need to login again. # @param [CopyleaksAuthToken] authToken Copyleaks authentication token def verify_auth_token(authToken) if authToken.nil? || !authToken.instance_of?(CopyleaksAuthToken) raise 'authToken is Invalid, must be instance of CopyleaksAuthToken' end _time = DateTime.now _expiresTime = DateTime.parse(authToken.expires) if _expiresTime <= _time raise AuthExipredException.new.reason # expired end end # Starting a new process by providing a file to scan. # For more info: # https://api.copyleaks.com/documentation/v3/scans/submit/file # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Copyleaks authentication token # @param [String] scanId Attach your own scan Id # @param [CopyleaksFileSubmissionModel] submission Submission properties def submit_file(authToken, scanId, submission) raise 'scanId is Invalid, must be instance of String' if scanId.nil? || !scanId.instance_of?(String) if submission.nil? || !submission.instance_of?(CopyleaksFileSubmissionModel) raise 'submission is Invalid, must be instance of type CopyleaksFileSubmissionModel' end verify_auth_token(authToken) path = "/v3/scans/submit/file/#{scanId}" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Put.new(path, headers) request.body = submission.to_json handle_response(@api_client.request(request), 'submit_file') end # Starting a new process by providing a OCR image file to scan. # For more info: # https://api.copyleaks.com/documentation/v3/scans/submit/ocr # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Copyleaks authentication token # @param [String] scanId Attach your own scan Id # @param [CopyleaksFileOcrSubmissionModel] submission Submission properties def submit_file_ocr(authToken, scanId, submission) raise 'scanId is Invalid, must be instance of String' if scanId.nil? || !scanId.instance_of?(String) if submission.nil? || !submission.instance_of?(CopyleaksFileOcrSubmissionModel) raise 'submission is Invalid, must be instance of type CopyleaksFileOcrSubmissionModel' end verify_auth_token(authToken) path = "/v3/scans/submit/ocr/#{scanId}" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Put.new(path, headers) request.body = submission.to_json handle_response(@api_client.request(request), 'submit_file_ocr') end # Starting a new process by providing a URL to scan. # For more info: # https://api.copyleaks.com/documentation/v3/scans/submit/url # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Copyleaks authentication token # @param [String] scanId Attach your own scan Id # @param [CopyleaksURLSubmissionModel] submission Submission properties def submit_url(authToken, scanId, submission) raise 'scanId is Invalid, must be instance of String' if scanId.nil? || !scanId.instance_of?(String) if submission.nil? || !submission.instance_of?(CopyleaksURLSubmissionModel) raise 'submission is Invalid, must be instance of CopyleaksURLSubmissionModel' end verify_auth_token(authToken) path = "/v3/scans/submit/url/#{scanId}" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Put.new(path, headers) request.body = submission.to_json handle_response(@api_client.request(request), 'submit_url') end # Exporting scans artifact into your server. # For more info: # https://api.copyleaks.com/documentation/v3/downloads/export # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Your login token to Copyleaks server # @param [String] scanId The scan ID of the specific scan to export. # @param [String] exportId A new Id for the export process. # @param [CopyleaksExportModel] model Request of which artifact should be exported. def export(authToken, scanId, exportId, model) raise 'scanId is Invalid, must be instance of String' if scanId.nil? || !scanId.instance_of?(String) raise 'exportId is Invalid, must be instance of String' if exportId.nil? || !exportId.instance_of?(String) if model.nil? || !model.instance_of?(CopyleaksExportModel) raise 'model is Invalid, must be instance of type CopyleaksExportModel' end verify_auth_token(authToken) path = "/v3/downloads/#{scanId}/export/#{exportId}" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Post.new(path, headers) request.body = model.to_json handle_response(@api_client.request(request), 'export') end # Start scanning all the files you submitted for a price-check. # For more info: # https://api.copyleaks.com/documentation/v3/scans/start # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Your login token to Copyleaks server. # @param [CopyleaksStartRequestModel] data Include information about which scans should be started. def start(authToken, data) if data.nil? || !data.instance_of?(CopyleaksStartRequestModel) raise 'data is Invalid, must be instance of type CopyleaksStartRequestModel' end verify_auth_token(authToken) path = "/v3/scans/start" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Patch.new(path, headers) request.body = data.to_json handle_response(@api_client.request(request), 'start') end # Delete the specific process from the server. # For more info: # https://api.copyleaks.com/documentation/v3/scans/delete # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Copyleaks authentication token # @param [CopyleaksDeleteRequestModel] data def delete(authToken, data) if data.nil? || !data.instance_of?(CopyleaksDeleteRequestModel) raise 'data is Invalid, must be instance of CopyleaksDeleteRequestModel' end verify_auth_token(authToken) path = "/v3.1/scans/delete" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Patch.new(path, headers) request.body = data.to_json handle_response(@api_client.request(request), 'delete') end # Resend status webhooks for existing scans. # For more info: # https://api.copyleaks.com/documentation/v3/scans/webhook-resend # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # @param [CopyleaksAuthToken] authToken Copyleaks authentication token # @param [String] scanId Copyleaks scan Id def resend_webhook(authToken, scanId) raise 'scanId is Invalid, must be instance of String' if scanId.nil? || !scanId.instance_of?(String) verify_auth_token(authToken) path = "/v3/scans/#{scanId}/webhooks/resend" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Post.new(path, headers) handle_response(@api_client.request(request), 'resend_webhook') end # Get current credits balance for the Copyleaks account. # For more info: # https://api.copyleaks.com/documentation/v3/scans/credits # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # * * RateLimitException: Too many requests. Please wait before calling again. # @param [CopyleaksAuthToken] authToken Copyleaks authentication token def get_credits_balance(authToken) verify_auth_token(authToken) path = "/v3/scans/credits" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Get.new(path, headers) handle_response(@api_client.request(request), 'get_credits_balance') end # This endpoint allows you to export your usage history between two dates. # The output results will be exported to a csv file and it will be attached to the response. # For more info: # https://api.copyleaks.com/documentation/v3/scans/usages/history # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # * * RateLimitException: Too many requests. Please wait before calling again. # @param [CopyleaksAuthToken] authToken Copyleaks authentication token. # @param [String] startDate The start date to collect usage history from. Date Format: `dd-MM-yyyy`. # @param [String] endDate The end date to collect usage history from. Date Format: `dd-MM-yyyy`. def get_usages_history_csv(authToken, startDate, endDate) raise 'startDate is Invalid, must be instance of String' if startDate.nil? || !startDate.instance_of?(String) raise 'endDate is Invalid, must be instance of String' if endDate.nil? || !endDate.instance_of?(String) verify_auth_token(authToken) path = "/v3/scans/usages/history?start=#{startDate}&end=#{endDate}" headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent, 'Authorization' => "Bearer #{authToken.accessToken}" } request = Net::HTTP::Get.new(path, headers) handle_response(@api_client.request(request), 'get_usages_history_csv') end # Get a list of the supported languages for OCR (this is not a list of supported languages for the api, but only for the OCR files scan). # For more info: https://api.copyleaks.com/documentation/v3/specifications/ocr-languages/list # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # * * RateLimitException: Too many requests. Please wait before calling again. # @return array List of supported OCR languages. def get_ocr_supported_languages path = '/v3/miscellaneous/ocr-languages-list' headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent } request = Net::HTTP::Get.new(path, headers) handle_response(@api_client.request(request), 'get_ocr_supported_languages') end # Get a list of the supported file types. # For more info: https://api.copyleaks.com/documentation/v3/specifications/supported-file-types # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # * * RateLimitException: Too many requests. Please wait before calling again. # @return mixed List of supported file types. def get_supported_file_types path = '/v3/miscellaneous/supported-file-types' headers = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent } request = Net::HTTP::Get.new(path, headers) handle_response(@api_client.request(request), 'get_supported_file_types') end # Get updates about copyleaks api release notes. # For more info: https://api.copyleaks.com/documentation/v3/release-notes # * Exceptions: # * * CommandExceptions: Server reject the request. See response status code, # headers and content for more info. # * * UnderMaintenanceException: Copyleaks servers are unavailable for maintenance. # We recommend to implement exponential backoff algorithm as described here: # https://api.copyleaks.com/documentation/v3/exponential-backoff # * * RateLimitException: Too many requests. Please wait before calling again. # @return mixed List of release notes. def get_release_notes path = '/v3/release-logs.json' header = { 'Content-Type' => 'application/json', 'User-Agent' => Config.user_agent } request = Net::HTTP::Get.new(path, header) handle_response(@api_client.request(request), 'get_release_notes') end # this methods is a helper for hanlding reponse data and exceptions. def handle_response(response, used_by) if Utils.is_success_status_code(response.code) if response.body.nil? || response.body == '' nil else JSON.parse(response.body) end elsif Utils.is_under_maintenance_response(response.code) raise UnderMaintenanceException.new.reason elsif Utils.is_rate_limit_response(response.code) raise RateLimitException.new.reason else _err_message = '---------Copyleaks SDK Error (' + used_by + ')---------' + "\n\n" _err_message += 'status code: ' + response.code + "\n\n" _err_message += 'response body:' + "\n" + response.body.to_json + "\n\n" unless response.body.nil? _err_message += '-------------------------------------' raise CommandException.new(_err_message).reason + "\n" end end end end