Indy + SSL + API i "Could not load SSL library"

0

Witam.
Od jakiegoś czasu próbuję napisać aplikację do komunikacji z API na pln.bitcurex.com.
Niestety mam z tym sporo problemów. Aktualnie ma taki efekt :

Przy pierwszym wywołaniu funkcji dostaję komunikat (błąd) : Could not load SSL library
natomiast za drugim i kolejnymi razami jest OK.

Szukałem na google i na forum: próbowałem dodać timeout na 5000, redirect an true oraz wgrać bibloteki dll bezpośrednio do katalogu gdzie jest exek. Niestety to nie pomaga.

Mogę oczywiście ominąć problem wywołując funkcję 2 razy (za pierwszym razem w bloku try..except) i będzie OK - ale nie chcę problemu omijać tylko go rozwiązać.

Będę wdzięczny za wszystkie sugestie.

Środowisko : (WinXP/Win7) + TurboDelphi Prof.

procedure TForm1.Button1Click(Sender: TObject);
var
  http    : TIdHTTP;
  iossl   : TIdSSLIOHandlerSocketOpenSSL;
  msResp  : TStringStream;
const
  Link1   = 'https://pln.bitcurex.com/data/ticker.json';
  Link2   = 'https://pln.bitcurex.com/data/orderbook.json';
  Link3   = 'https://pln.bitcurex.com/data/trades.json';
begin
  http    := TIdHTTP.Create(nil);
  iossl   := TIdSSLIOHandlerSocketOpenSSL.Create(http);
  msResp  := TStringStream.Create('');

  iossl.SSLOptions.Method := sslvSSLv3;
  http.IOHandler    := iossl;
  http.ReadTimeout  := 3000;
  try
    http.Get(Link1,msResp);
  finally
    Memo1.Lines.Text := msResp.DataString;
    msResp.Free;
    iossl.Free;
    http.Free;
  end;
end;

0

Możesz podać nazwy i wersje bibliotek jakie wgrałeś? No i wersję Indy.

0
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
  IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler;

Indy: 10.1.5

Bibloteki: OpenSSL v1.0.1e

libeay32.dll , ssleay32.dll

Próbowałem na starszych: indy 9.x.x, ale ten sam efekt

1

Wynika to z tego że nie znajduje tych DLL lub znajduje zaś nie są oni w odpowiedniej wersji.
Rozwiązanie najszybsze: do folderu programu wgrać odpowiednią wersję tych DLL'ek

2

U mnie na tej wersji śmigają jakieś stare biblioteki z 2004r. (nie mają numeru wersji) http://www.speedyshare.com/48YGf/ssl.rar
EDIT: nowy link bo widze ze tamta strona dodaje jakieś śmieszne programy do pobierania http://wyslijto.pl/plik/jq149y41gg

0

Faktycznie na tych starych bibliotekach działa bez problemów !!!
Serdeczne podziękowania :)

0

Witam. U mnie również działa poprawnie po pobraniu starszych bibliotek. Wystarczy sobie to sprasować i ładnie wyświetlić. Mam jednak pytanie czy istnieje jakaś możliwość obsługi prywatnego API bitcurex-a z poziomu delphi? Nie mam zielonego pojęcia na jakiej zasadzie miało by to działać. Jedyne co podano na stronie to adres tego api https://pln.bitcurex.com/api/0/ po którego wpisaniu pokazuje się błąd 403 oraz opisy metod np:

getFunds - pobiera aktualne saldo dostępne konta i adres zasileń BTC
POST: nonce=#, zwrot: plns, btcs, address

sellBTC - ustawia zlecenie sprzedaży BTC (ASK)
POST: nonce=#&amount=#&price=#, zwrot: plns, btcs, orders

itd. Nic więcej nie zostało podane na stronie. Podejrzewam, że to dość istotne to z góry mówię, że klucz API i klucz sekretny już posiadam.

Z góry dziękuję za wszelką pomoc

0

Faktycznie mało precyzyjne tak opisane API. Wiadomo tylko mniej wiecej co wysłać POSTem, ale dokładnych urli brak. A ja myślałem że API ryjoksiążki jest badziewnie opisane, bo w zaprojektowamej stronie z opisami panuje imo lekki chaos. Weź może na próbę postnij żywcem takie dane jak podali na stronagłówna/tocoprzedparametrami i zobacz co zwróci. Jeżeli nadal 403, to ja nic nie wymyślę.

0

Po zastosowaniu takiego kodu:

procedure TForm1.Button2Click(Sender: TObject);
var
  http    : TIdHTTP;
  iossl   : TIdSSLIOHandlerSocketOpenSSL;
  post    : TIdMultiPartFormDataStream;
  s       : string;
const
  link = 'https://pln.bitcurex.com/api/0/';
begin
  http    := TIdHTTP.Create(nil);
  post := TIdMultiPartFormDataStream.Create;
  iossl   := TIdSSLIOHandlerSocketOpenSSL.Create(http);

  iossl.SSLOptions.Method := sslvSSLv3;
  http.IOHandler    := iossl;
  http.ReadTimeout  := 3000;
  post.AddFormField('nonce', 'getFunds');
  s := http.Post(link, post);
  memo1.Text := s;
end;

Pokazuje mi się komunikat socket error # 0. Generalnie jak tylko użyję funkcji post to taki komunikat się pojawia. Przy wpisaniu tego adresu w get otrzymuję:

{"methods":[{"name":"getFunds","post":"nonce=#","result":"funds"},{"name":"getOrders","post":"nonce=#","result":"funds and orders"},{"name":"buyBTC","post":"nonce=#&amount=#&price=#","result":"funds and orders"},{"name":"sellBTC","post":"nonce=#&amount=#&price=#","result":"funds and orders"},{"name":"cancelOrder","post":"nonce=#&oid=#&type=#","result":"funds and orders"},{"name":"getTransactions","post":"nonce=#","result":"last 100 transactions"},{"name":"withdraw","post":"nonce=#&type=#&amount=#","result":"funds"}]}

Nie wiem czy to coś z moim kodem czy trzeba jakoś podać ten swój klucz API prywatny

--------------------- Dodano później ;)

Znalazłem taki kod w pythonie (z czym nigdy odczynienia nie miałem) który mnie nakierował na to, że dane logowania muszą być w nagłówku. Problem w tym, że nie wystarczy zwykłe podanie prywatnego klucza a jakieś kombinacje z HMAC o którym pierwszy raz słyszę. Ma ktoś jakiś pomysł jak to w delphi zaimplementować?

import math
import time
import simplejson
import urllib
import urllib2
import hmac,hashlib

def microtime():
    return '%f %d' % math.modf(time.time())

def query( path, key, secret, data={} ):
    mt = microtime().split()
    nonce = mt[1] + mt[0][2:]
    data['nonce'] = nonce

    post_data = urllib.urlencode( data )

    sign = hmac.new( secret.decode('base64'), post_data, hashlib.sha512 ).digest()

    headers = {'Rest-Key' : key,
               'Rest-Sign': sign.encode('base64').strip(),
               'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
               'Content-type': 'application/x-www-form-urlencoded'}
    print headers

    url = 'https://bitcurex.com/api/0/' + path

    req = urllib2.Request( url, post_data, headers )
    response = urllib2.urlopen(req)

    return simplejson.loads(response.read())

print query('getFunds', '29a28e8fe234537056a8b256c0df50413f50da9c49ca61991ea8b8f108a88e09',  'y2NDxKGa/xvhtXrDP+3oscbBUFSac9+T8jzu2nRmt0vBdHbbl8NRqdmxKFr2IwwY5LAskTQZGyy2XONaNN6Jrg==')

Generalnie cały mój kod (nie ten wyżej) działa chyba poprawnie bo zwraca informację o potrzebie zalogowania tylko całe to mixowanie klucza prywatnego jest dla mnie czarną magią :(
Tutaj link do strony gdzie kod znalazłem: http://stackoverflow.com/questions/13893824/translating-php-to-python-rest-api-connection

1

To ustaw nagłówki same się nie ustawią:

  IdHTTP1.Request.UserAgent:= 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)';
  IdHTTP1.Request.ContentType:= 'application/x-www-form-urlencoded';
  IdHTTP1.Request.RawHeaders.AddStrings('Rest-Key=' + key);
  IdHTTP1.Request.RawHeaders.AddStrings('Rest-Sign=' +  sign);
0

Nagłówki mam już ustawione ale chodzi o to, że Rest-Sign nie jest wysyłany w takiej postaci jaką mam tylko jest jakoś kodowany/dekodowany i nie wiem jak otrzymać identyczny efekt w delphi

0

Jakiej wersji Delphi używasz? Po mojemu (nie znam Pythona) to ten sign trzeba zakodować base64.

0

delphi 2010. tam to jest jakoś kodowanie w hmac512 i w środku jest rozkodowany base64 i jakieś kombinacje z datą co w tym momencie jest dla mnie największym problemem. Poniżej mam kod php który robi to samo i na nim teraz bazuję. Kod z forum 4p

function query(path, $key = '', $secret = '', array $req = array()) {
    //generates a timestamp to the request (required for authentication)
    $mt = explode(' ', microtime());
    req['nonce'] = $mt[1].substr($mt[0], 2, 6);
 
    //prepare POST data
    post_data = http_build_query($req, '', '&');
 
    //authorization headers
    headers = array(
        'Rest-Key: ' . $key,
        'Rest-Sign: ' . base64_encode(hash_hmac('sha512', $post_data, base64_decode($secret), true)),
    );
 
    //CURL initialization
    static $ch = null;
    if (is_null($ch)) {
        ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt(ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Bitcurex PHP client; ' . php_uname('s') . '; PHP/' . phpversion() . ')');
    }
 
    curl_setopt(ch, CURLOPT_URL, 'https://domena.pl/' . path);
    curl_setopt(ch, CURLOPT_POSTFIELDS, post_data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, headers);
 
    //executes the query
    res = curl_exec($ch);
    if (res === false) throw new Exception('Could not get reply: ' . curl_error($ch));
    res = json_decode($res, true);
    if (!res) {
        throw new Exception('Invalid data received, please make sure connection is working and requested API exists');
    }
    return res;
}
0

Całkiem przypadkiem znalazłem rozwiązanie głównego problemu wątku.

Aby biblioteki ładowały się wystarczy dodać np. z OnShow:

IdSSLOpenSSLHeaders.Load;

i działa z najnowszymi wersjami libeay32.dll i ssleay32.dll

Co do kwestii API na bicurexie, to dostaję cały czas :
{"error":"Must be logged in"}

Nie jestem tylko pewien, czy to że nie mogę się połączyć nie jest powodem tego, że API na bitcurexie jest "wyłączone do odwołania" (gdzieś coś takiego przeczytałem).

Czy może ktoś potwierdzić, że to API w ogóle działa ? (pyton, php, java, cokolwiek ?)

1 użytkowników online, w tym zalogowanych: 0, gości: 1