require 'yaml' class License include HTTParty include ActionDispatch::Http base_uri "https://l.doemal.app//api" attr_accessor :name, :address_1, :address_2, :township, :city, :country, :email, :phone, :fax, :logo, :subdomain, :plan_activation_date, :plan_next_renewal_date, :plan_max_products,:plan_max_customers, :plan_active_connections, :dbhost, :dbschema, :dbusername, :dbpassword, :exchange_unqiue_id, :localqueue_host,:server_mode,:localhost_address, :localqueue_user, :localqueue_password, :remotequeue_host, :remotequeue_user, :remotequeue_password, :api_token, :app_token, :lookup @license = nil @secret = nil def initialize(server = "", lookup = "") #this code is hard-code to reflect server mode - Very important. self.server_mode = ENV["SERVER_MODE"] unless ENV["SERVER_MODE"] == "cloud" self.server_mode = "application" end self.lookup = lookup if (server != "") self.class.base_uri server end end # For Cloud def detail_with_local_cache aes = MyAesCrypt.new aes_key, aes_iv = aes.export_to_file(lookup) ##Check from local redis - if available load local otherwise get from remote cache_key = "#{lookup}:license:#{aes_key}:hostname" cache_license = nil ##Get redis connection from connection pool redis = Redis.new(url: ENV['REDIS_URL']) cache_license = redis.get(cache_key) Rails.logger.info "Cache key - " + cache_key.to_s if cache_license.nil? ##change the d/e key # @options = { query: {device: "SXlite", lookup: lookup, skey: @secret, token: SECRETS_CONFIG['provision_key']} } @params = { query: { lookup_type: self.server_mode, lookup: lookup, iv_key: aes_iv} } response = self.class.get("/subdomain", @params.merge(get_predefined_ssl_version)) @license = response.parsed_response Rails.logger.info "License Response - " + response.parsed_response.to_s if (@license["status"] == true) assign(aes_key, aes_iv) #Rails.logger.info "License - " + response.parsed_response.to_s redis = Redis.new(url: ENV['REDIS_URL']) redis.set(cache_key, Marshal.dump(@license)) # redis.sadd("License:cache:keys", cache_key) # Redis.current do |conn| # ##Remote - store the remote response in local redis cache # conn.set(cache_key, Marshal.dump(@license)) # ##ADD to List to remove later # conn.sadd("License:cache:keys", cache_key) # end return true end else @license = Marshal.load(cache_license) assign(aes_key, aes_iv) # Rails.logger.info 'API License' return true end end # For Local System def detail_with_local_file if expired? return 0 elsif expire_in?(10) return 2 else return 1 end end # License Activation def license_activate (shop, license_key, db_host, db_schema, db_user, db_password) aes = MyAesCrypt.new aes_key, aes_iv = aes.export_key(license_key) @params = { query: { lookup_type: self.server_mode, iv_key: aes_iv, license_key: license_key } } begin response = self.class.get("/activate", @params.merge(get_predefined_ssl_version)) @activate = response.parsed_response if (@activate["status"]) ##Check from local redis - if available load local otherwise get from remote cache_key = "shop:#{@activate["shop_name"]}" ##Get redis connection from connection pool # redis = Redis.new # cache_license = redis.get(cache_key) Rails.logger.info "Cache key - " + cache_key.to_s # if cache_license.nil? cache = {"shop" => @activate["shop_name"], "key" => aes_key, "iv" => @activate["iv_key"], "renewable_date" => @activate["renewable_date"] } redis = Redis.new(url: ENV['REDIS_URL']) redis.set(cache_key, Marshal.dump(cache)) # end Rails.logger.info "License - " + response.parsed_response.to_s response = create_license_file(@activate) if(response[:status]) #sym_path = "/home/user/symmetric/" sym_path = File.expand_path("~/symmetric/") response = create_symmetric_config(sym_path, db_host, db_schema, db_user, db_password) if(response[:status]) response = run_symmetric(sym_path) end end else response = { "status": false, "message": "Activation Failed! Please contact code2lab call center!"} end rescue SocketError => e Rails.logger.debug "In SocketError No Internet connection !" response = { "status": false, "message": "In SocketError No Internet connection !"} rescue HTTParty::Error Rails.logger.debug "Server Error HTTParty" response = { "status": false, "message": "Server Error HTTParty"} rescue Net::OpenTimeout Rails.logger.debug "connection Timeout" response = { "status": false, "message": "Connection Timeout"} rescue OpenURI::HTTPError Rails.logger.debug "Can't connect server" response = { "status": false, "message": "Can't connect server"} end return response end def verify_license api_token = read_license_no_decrypt("api_token") @params = { query: {lookup_type: "application", api_token: api_token} } begin response = self.class.get("/verify", @params.merge(get_predefined_ssl_version)) @varified = response.parsed_response Rails.logger.debug "License Remote Response - " + response.parsed_response.to_s if (@varified["status"]) old_renewable_date = read_license("renewable_date") if old_renewable_date.to_date < @varified['renewable_date'].to_date update_license("renewable_date", @varified['renewable_date']) return true end end rescue SocketError => e Rails.logger.debug "In SocketError No Internet connection ! " rescue HTTParty::Error Rails.logger.debug "Server Error HTTParty" rescue Net::OpenTimeout Rails.logger.debug "connection Timeout" rescue OpenURI::HTTPError Rails.logger.debug "Can't connect server" end return false end def exists? License.check_license_file(lookup) end def expired? if renewal_date_str = read_license("renewable_date") renewal_date = Time.zone.parse(renewal_date_str) renewal_date < Date.current end end def expire_in?(days) if renewal_date_str = read_license("renewable_date") renewal_date = Time.zone.parse(renewal_date_str) renewal_date < days.days.from_now end end def days_to_expire if renewal_date_str = read_license("renewable_date") Date.current - Time.zone.parse(renewal_date_str).to_date end end # Check License expired date from PROVISION SERVER def check_expired(renewal_date_str) expired_date_str = read_license("renewable_date") renewal_date = Time.zone.parse(renewal_date_str) if(renewal_date_str != expired_date_str) update_license("renewable_date", renewal_date_str) end if (renewal_date < Date.current) return true else return false end end def check_license_subdomain aes = MyAesCrypt.new aes_key, aes_iv = aes.export_key(lookup) params = { query: { lookup_type: "cloud", lookup: lookup, iv_key: aes_iv} } response = self.class.get("/subdomain", params.merge(get_predefined_ssl_version)) response.parsed_response["status"] rescue end # Check License File exists def self.check_license_file(lookup) return unless File.exist?("config/license.yml") if license = YAML.load_file("config/license.yml") if license[lookup].nil? if license['iv_key'] license = { lookup => license } else tld_length = Rails.application.config.action_dispatch.tld_length subdomains = URL.extract_subdomains(lookup, tld_length) if subdomains.first && subdomains.first != 'www' if key = license.keys.find { |k| URL.extract_subdomains(k, tld_length).first == subdomains.first} license[lookup] = license[key] end else license[lookup] = license.values.first end end if license[lookup] File.open("config/license.yml", "w") { |file| file.write license.to_yaml } end end return license[lookup] end end # read line by key for license file def read_license(key_name) if File.exist?("config/license.yml") key, iv = get_redis_key() if license = YAML.load(File.read("config/license.yml")) if license[lookup] AESCrypt.decrypt_data(decode_str(license[lookup][key_name]), decode_str(key), decode_str(iv), ENV['CIPHER_TYPE']) end end end end # read line by key for license file without decrypt def read_license_no_decrypt(key) if File.exist?("config/license.yml") if license = YAML.load_file("config/license.yml") if license[lookup] decrypted_line = license[lookup][key] end end end end # Update license file for line def update_license(content, new_content) if File.exist?("config/license.yml") key, iv = get_redis_key() if !new_content.include? "==" crypted_str = AESCrypt.encrypt_data(new_content, decode_str(key), decode_str(iv), ENV['CIPHER_TYPE']) end if license = YAML.load_file("config/license.yml") license[lookup][content] = encode_str(crypted_str) # To write changes to the file, use: File.open("config/license.yml", "w") {|file| file.write(license.to_yaml) } end end end # Re-get keys def get_key api_token = read_license_no_decrypt("api_token") shop_name = read_license_no_decrypt("shop_name") @params = { query: {lookup_type: "application", api_token: api_token } } response = self.class.get("/get_key", @params.merge(get_predefined_ssl_version)) @data = response.parsed_response if (@data["status"]) ##Check from local redis - if available load local otherwise get from remote cache_key = "shop:#{shop_name.chomp}" cache_license = nil ##Get redis connection from connection pool redis = Redis.new(url: ENV['REDIS_URL']) cache_license = redis.get(cache_key) Rails.logger.info "Cache key - " + cache_key.to_s if cache_license.nil? cache = {"shop" => shop_name, "key" => @data["secret_key"], "iv" => @data["iv_key"], "renewable_date" => @data["renewable_date"] } redis = Redis.new(url: ENV['REDIS_URL']) redis.set(cache_key, Marshal.dump(cache)) end return true end return false end private def get_redis_key iv = "" key = "" shop = read_license_no_decrypt("shop_name") ##Check from local redis - if available load local otherwise get from remote cache_key = "shop:#{shop.chomp}" ##Get redis connection from connection pool redis = Redis.new(url: ENV['REDIS_URL']) cache_shop = redis.get(cache_key) puts Marshal.load(cache_shop) if !cache_shop.nil? @shop = Marshal.load(cache_shop) key = @shop["key"] iv = @shop["iv"] end return key, iv end def encode_str(str) return Base64.encode64(str) end def decode_str(str) return Base64.decode64(str) end # License File Creation def create_license_file(response_data) begin # Licese File Creation config = { "iv_key" => response_data['iv_key'], "shop_name" => response_data['shop_name'], "email" => response_data['email'], "telephone" => response_data['telephone'], "fax" => response_data['fax'], "address" => response_data['address'], "dbhost" => response_data['dbhost'], "dbschema" => response_data['dbschema'], "dbusername" => response_data['dbusername'], "dbpassword" => response_data['dbpassword'], "api_token" => response_data['api_token'], "app_token" => response_data['app_token'], "plan_sku" => response_data['plan_sku'], "renewable_date" => response_data['renewable_date'], "plan_name" => response_data['plan_name'] } if File.exist?("config/license.yml") license = YAML.load_file("config/license.yml") end if license license.each do |k,v| license[k] = config if v["shop_name"] == config["shop_name"] end license[lookup] = config end license ||= {lookup => config} File.open("config/license.yml", "w"){ |file| file.write(license.to_yaml) } rescue IOError response = { "status": false, "message": "Activation is success but something is wrong. \n Please contact code2lab call center!"} end response = { "status": true, "message": "Success Activation. License also created."} end # Symmetric Configuration def create_symmetric_config(sym_location, db_host, db_schema, db_user, db_password) if File.directory? (sym_location) begin # sx properties create f = File.open(sym_location + "/engines/sx.properties", "w") f.write("engine.name=sx\n") f.write("db.driver=com.mysql.jdbc.Driver\n") f.write("db.url=jdbc:mysql://#{db_host}/#{db_schema}?tinyInt1isBit=false\n") f.write("db.user=#{db_user}\n") f.write("db.password=#{db_password}\n") f.write("registration.url=\n") f.write("sync.url=http://#{db_host}:31415/sync/sx\n") f.write("group.id=sx\n") f.write("external.id=000\n") f.write("job.purge.period.time.ms=7200000\n") f.write("job.routing.period.time.ms=5000\n") f.write("job.push.period.time.ms=10000\n") f.write("job.pull.period.time.ms=10000\n") f.write("initial.load.create.first=true\n") f.write("initial.load.use.extract.job.enabled=true\n") f.write("rest.api.enable=true\n") f.close # read from license file # shop_name = read_license_no_decrypt("shop_name") shop_name = "cloud" dbhost = read_license("dbhost") dbschema = read_license("dbschema") dbusername = read_license("dbusername") dbpassword = read_license("dbpassword") # shop properties create f = File.open(sym_location + "/engines/#{shop_name}.properties", "w") f.write("engine.name=#{shop_name}\n") f.write("db.driver=com.mysql.jdbc.Driver\n") f.write("db.url=jdbc:mysql://#{dbhost}/#{dbschema}?tinyInt1isBit=false\n") f.write("db.user=#{dbusername}\n") f.write("db.password=#{dbpassword}\n") f.write("registration.url=http://#{db_host}:31415/sync/sx\n") f.write("group.id=cloud\n") f.write("external.id=001\n") f.write("job.routing.period.time.ms=5000\n") f.write("job.push.period.time.ms=10000\n") f.write("job.pull.period.time.ms=10000\n") f.write("rest.api.enable=true\n") # f.write("initial.load.create.first=true\n") # f.write("initial.load.use.extract.job.enabled=true\n") f.close rescue IOError return { "status": false, "message": "Activation is success but something is wrong. \n Please contact code2lab call center!"} end end { "status": true, "message": "Success Activation. License also created." } end # Run Symmetric def run_symmetric(sym_path) # check_sym_proc_str = `#{sym_path + "bin/sym_service status"}` # check_sym_proc_str = check_sym_proc_str.split("\n") # sym_install_status = check_sym_proc_str[0].split(": ") check_sym_proc_str = `#{"sudo service SymmetricDS status"}` # Check Sym Installed # if sym_install_status[1] == "false" # response = { "status": false, "message": "Activation is success but Symmetric service not Installed. \n Please contact code2lab call center!"} # end # Run Sym Service sym_run_status = check_sym_running(check_sym_proc_str, sym_path) if sym_run_status # Create Sym Table check_sym_table = system("sudo " + sym_path + "/bin/symadmin --engine sx create-sym-tables") if check_sym_table sym_sql = Rails.root + "db/sym_master.sql" if File.exist? (sym_sql) # Import Sym Sql to db and start sym run_sym_sql = system("sudo " + sym_path + "/bin/dbimport --engine sx " + sym_sql.to_s) stop_sym = system("sudo service SymmetricDS stop") run_sym = system("sudo service SymmetricDS start") if run_sym response = { "status": true, "message": "Activation is success and Configuration done..."} end else response = { "status": false, "message": "Activation is success but Symmetric Sql not found. \n Please contact code2lab call center!"} end else response = { "status": false, "message": "Activation is success but Cannot create Sym Tables. \n Please contact code2lab call center!"} end else response = { "status": false, "message": "Activation is success but Symmetric not running. \n Please contact code2lab call center!"} end end # Check Symmetric Running def check_sym_running(status, sym_path) # Run Sym Service # if status.include? "Server is already running" # return true # elsif status.include? "false" # sym_start_str = `#{sym_path + "bin/sym_service start"}` # if sym_start_str.include? "Started" # return true # else # check_sym_running(sym_start_status[0]) # end # else # return true # end if status.include? "Active: active (running)" || "Active: active (exited)" #"Server is already running" return true end return false end # Delete License File def delete_license_file File.delete("config/license.yml") if File.exist?("config/license.yml") end # Assign db info for Cloud def assign(aes_key, aes_iv) key = Base64.decode64(aes_key) iv = Base64.decode64(aes_iv) if (@license["dbhost"] || @license["dbschema"] || @license["dbusername"] || @license["dbpassword"] ) host = Base64.decode64(@license["dbhost"]) dbschema = Base64.decode64(@license["dbschema"]) dbusername = Base64.decode64(@license["dbusername"]) dbpassword = Base64.decode64(@license["dbpassword"]) self.dbhost = AESCrypt.decrypt_data(host, key, iv, ENV['CIPHER_TYPE']) self.dbschema = AESCrypt.decrypt_data(dbschema, key, iv, ENV['CIPHER_TYPE']) self.dbusername = AESCrypt.decrypt_data(dbusername, key, iv, ENV['CIPHER_TYPE']) self.dbpassword = AESCrypt.decrypt_data(dbpassword, key, iv, ENV['CIPHER_TYPE']) end end private def get_predefined_ssl_version { verify: true, ssl_version: :TLSv1_2 } end end