Commit dadb2bc
Changed files (4)
lib/elelem/api.rb
@@ -28,7 +28,7 @@ module Elelem
{
open_timeout: 10,
read_timeout: 3_600,
- use_ssl: uri.scheme == 'https',
+ use_ssl: uri.scheme == "https"
}
end
@@ -39,50 +39,49 @@ module Elelem
# No scheme โ decide which one to add.
# * localhost or 127.0.0.1 โ http
# * anything else โ https
- if raw_host.start_with?('localhost', '127.0.0.1')
- scheme = 'http://'
- else
- scheme = 'https://'
- end
+ scheme = raw_host.start_with?("localhost", "127.0.0.1") ? "http://" : "https://"
host = scheme + raw_host
end
- endpoint = "#{host.sub(%r{/?$}, '')}/api/chat"
- URI(endpoint)
+ URI("#{host.sub(%r{/?$}, "")}/api/chat")
end
def build_request(messages)
- Net::HTTP::Post.new(uri).tap do |request|
+ timestamp = Time.now.to_i
+ request_uri = build_uri_with(timestamp)
+ Net::HTTP::Post.new(request_uri).tap do |request|
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request["User-Agent"] = "ollama/0.11.3 (amd64 linux) Go/go1.24.6"
- build_token do |token|
+ build_token("POST", request_uri.path, timestamp) do |token|
request["Authorization"] = token
end
request.body = build_payload(messages).to_json
end
end
- def build_token
+ def build_uri_with(timestamp)
+ uri.dup.tap do |request_uri|
+ original_query = request_uri.query
+ request_uri.query = original_query ? "#{original_query}&ts=#{timestamp}" : "ts=#{timestamp}"
+ end
+ end
+
+ def build_token(method, path, timestamp)
if uri.host == "ollama.com"
- raise "Not Implemented"
+ private_key_path = File.expand_path("~/.ollama/id_ed25519")
+ raise "Ollama Ed25519 key not found at #{private_key_path}" unless File.exist?(private_key_path)
- # if File.exist?("~/.ollama/id_ed25519")
- # TODO:: return signature
- # now := strconv.FormatInt(time.Now().Unix(), 10)
- # challenge := fmt.Sprintf("%s,%s?ts=%s", method, path, now)
- # token, err := auth.Sign(ctx, []byte(challenge))
- # q := requestURL.Query()
- # q.Set("ts", now)
- # requestURL.RawQuery = q.Encode()
- #
- # request["Authorization"] = token
- # end
+ challenge = "#{method},#{path}?ts=#{timestamp}"
+ private_key = load_ed25519_key(private_key_path)
+ signature = private_key.sign(challenge)
+ encoded_signature = Base64.strict_encode64(signature)
+ yield encoded_signature
end
- if configuration.token && !configuration.token.empty?
- yield "Bearer #{configuration.token}"
- end
+ return unless configuration.token && !configuration.token.empty?
+
+ yield "Bearer #{configuration.token}"
end
def build_payload(messages)
@@ -97,5 +96,10 @@ module Elelem
configuration.logger.debug(JSON.pretty_generate(payload))
end
end
+
+ def load_ed25519_key(key_path)
+ ssh_key = Net::SSH::KeyFactory.load_private_key(key_path)
+ Ed25519::SigningKey.new(ssh_key.sign_key.seed)
+ end
end
end
lib/elelem.rb
@@ -1,11 +1,14 @@
# frozen_string_literal: true
+require "base64"
require "cli/ui"
+require "ed25519"
require "erb"
require "json"
require "json-schema"
require "logger"
require "net/http"
+require "net/ssh"
require "open3"
require "reline"
require "thor"
elelem.gemspec
@@ -61,12 +61,16 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
+ spec.add_dependency "base64"
+ spec.add_dependency "bcrypt_pbkdf"
spec.add_dependency "cli-ui"
+ spec.add_dependency "ed25519"
spec.add_dependency "erb"
spec.add_dependency "json"
spec.add_dependency "json-schema"
spec.add_dependency "logger"
spec.add_dependency "net-http"
+ spec.add_dependency "net-ssh"
spec.add_dependency "open3"
spec.add_dependency "reline"
spec.add_dependency "thor"
Gemfile.lock
@@ -2,12 +2,16 @@ PATH
remote: .
specs:
elelem (0.1.3)
+ base64
+ bcrypt_pbkdf
cli-ui
+ ed25519
erb
json
json-schema
logger
net-http
+ net-ssh
open3
reline
thor
@@ -20,10 +24,13 @@ GEM
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
+ base64 (0.3.0)
+ bcrypt_pbkdf (1.1.1)
bigdecimal (3.2.2)
cli-ui (2.4.0)
date (3.4.1)
diff-lcs (1.6.2)
+ ed25519 (1.4.0)
erb (5.0.2)
io-console (0.8.1)
irb (1.15.2)
@@ -39,6 +46,7 @@ GEM
logger (1.7.0)
net-http (0.6.0)
uri
+ net-ssh (7.3.0)
open3 (0.2.1)
parallel (1.27.0)
parser (3.3.9.0)