mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-27 00:02:23 +01:00
Full daemon source (C, PS4 native): - log/cfg/jsonlite/b64: logging, /data/PS4RP/config.json, JSON, base64 - http.c: OAuth2 token exchange via SceHttp (authorization_code + refresh) - ws.c: WebSocket over SceNet + LibreSSL (SSLv23_client_method), DNS via sceNetResolverStartNtoa, OrbisNetSockaddr packing - discord.c: gateway connect/identify/heartbeat/presence set+clear - detect.c: foreground game via sceUserServiceGetForegroundUser + app.xml/app.db title-name resolution - main.c: poll loop (config poll_interval_s) Build verified on macOS (LLVM 21 + OpenOrbis toolchain v0.5.4): - 9 objects compile, lld 21 links build/ps4rp.elf (169KB) - create-fself produces valid SCE ASLR payload build/ps4rp.fself - libSceLibreSSL exports the OpenSSL-style TLS API used by ws.c
114 lines
5.6 KiB
C
114 lines
5.6 KiB
C
/* http.c - OAuth2 token endpoint via SceHttp. */
|
|
#include "http.h"
|
|
#include "cfg.h"
|
|
#include "log.h"
|
|
#include <stdbool.h>
|
|
#include <orbis/Sysmodule.h>
|
|
#include <orbis/Net.h>
|
|
#include <orbis/Http.h>
|
|
#include <orbis/Ssl.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define NET_POOL (64 * 1024)
|
|
#define SSL_PL (128 * 1024)
|
|
#define HTTP_PL (128 * 1024)
|
|
|
|
static int s_http_mem = 0, s_ssl_mem = 0, s_http_ctx = 0; /* ids */
|
|
|
|
/* NOTE: SceHttp/SSL headers declare funcs as void() stubs; we call them
|
|
* with the real argument layout (no local redeclaration to avoid conflicts). */
|
|
static int http_init(void){
|
|
if(s_http_ctx) return 0;
|
|
int r;
|
|
uint32_t ur = sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_NET);
|
|
r=(int)ur;
|
|
if(r<0){log_msg("load NET fail %d",r);return -1;}
|
|
if((r=sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_HTTP))<0){log_msg("load HTTP fail %d",r);return -2;}
|
|
if((r=sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_SSL))<0){log_msg("load SSL fail %d",r);return -3;}
|
|
if((r=sceNetInit())<0){log_msg("sceNetInit %d",r);return -4;}
|
|
s_http_mem=(int)sceNetPoolCreate("ps4rpN",NET_POOL,0); if(s_http_mem<0){log_msg("netpool %d",s_http_mem);return -5;}
|
|
s_ssl_mem=(int)sceSslInit(SSL_PL); if(s_ssl_mem<0){log_msg("sslinit %d",s_ssl_mem);return -6;}
|
|
if((r=sceHttpInit(s_http_mem,s_ssl_mem,HTTP_PL))<0){log_msg("httpinit %d",r);return -7;}
|
|
s_http_ctx=r;
|
|
return 0;
|
|
}
|
|
|
|
/* --- json helpers (avoid coupling to cfg's parser) --- */
|
|
static void jstr(const char *js,const char *key,char *out,size_t cap){
|
|
char k[64]; size_t kl=strlen(key); if(kl>=sizeof k){if(out)*out=0;return;}
|
|
k[0]='\"'; memcpy(k+1,key,kl); k[1+kl]='\"'; k[2+kl]=0;
|
|
const char *p=strstr(js,k); if(!p||!out){if(out)*out=0;return;}
|
|
p+=2+kl; while(*p==' '||*p==':')p++;
|
|
size_t i=0;
|
|
if(*p=='"'){ p++; while(*p&&*p!='"'&&i<cap-1){out[i++]=*p++;} }
|
|
else { while(*p&&*p>='0'&&*p<='9'&&i<cap-1){out[i++]=*p++;} }
|
|
out[i]=0;
|
|
}
|
|
static long jnum(const char *js,const char *key){
|
|
char k[64]; size_t kl=strlen(key); if(kl>=sizeof k)return 0;
|
|
k[0]='\"'; memcpy(k+1,key,kl); k[1+kl]='\"'; k[2+kl]=0;
|
|
const char *p=strstr(js,k); if(!p)return 0;
|
|
p+=2+kl; while(*p==' '||*p==':')p++; return strtol(p,NULL,10);
|
|
}
|
|
|
|
int http_oauth_token(const char *client_id,const char *client_secret,
|
|
const char *code,const char *refresh_token,
|
|
char *access_token,size_t at_cap,
|
|
char *refresh_out,size_t rt_cap,
|
|
int64_t *expires_out_epoch){
|
|
if(http_init()) return -10;
|
|
int32_t tpl=0,conn=0,req=0,rc=0,status=0;
|
|
if(!(client_id&&*client_id)){log_msg("no client_id");return -11;}
|
|
char body[1024]; int blen=0;
|
|
blen+=snprintf(body+blen,sizeof body-blen,"client_id=%s",client_id?client_id:"");
|
|
if(client_secret&&*client_secret) blen+=snprintf(body+blen,sizeof body-blen,"&client_secret=%s",client_secret);
|
|
if(code&&*code) blen+=snprintf(body+blen,sizeof body-blen,
|
|
"&grant_type=authorization_code&code=%s&redirect_uri=%s", code, "http://localhost:6770/callback");
|
|
else if(refresh_token&&*refresh_token) blen+=snprintf(body+blen,sizeof body-blen,
|
|
"&grant_type=refresh_token&refresh_token=%s", refresh_token);
|
|
else blen+=snprintf(body+blen,sizeof body-blen,"&grant_type=client_credentials&scope=applications.commands");
|
|
const char *URL="https://discord.com/api/oauth2/token";
|
|
tpl=sceHttpCreateTemplate(s_http_ctx, "PS4RP/1.0", ORBIS_HTTP_VERSION_1_1, 0); if(tpl<0){log_msg("tmpl %d",tpl);rc=-1;goto done;}
|
|
conn=sceHttpCreateConnectionWithURL(tpl, URL, 0); if(conn<0){log_msg("conn %d",conn);rc=-2;goto done;}
|
|
req=sceHttpCreateRequestWithURL(conn, ORBIS_METHOD_POST, URL, (uint64_t)blen); if(req<0){log_msg("req %d",req);rc=-3;goto done;}
|
|
sceHttpAddRequestHeader(req,"Content-Type","application/x-www-form-urlencoded",0);
|
|
sceHttpAddRequestHeader(req,"User-Agent","PS4RP/1.0",0);
|
|
if((rc=sceHttpSendRequest(req,body,blen))<0){log_msg("send %d",rc);rc=-4;goto done;}
|
|
if((rc=sceHttpGetStatusCode(req,&status))<0){log_msg("stat %d",rc);rc=-5;goto done;}
|
|
char resp[2048]; int total=0,len;
|
|
while((len=sceHttpReadData(req,resp+total,sizeof resp-total))>0){total+=len; if(total>(int)sizeof resp-1)break;}
|
|
resp[total>= (int)sizeof resp? (int)sizeof resp-1:total]=0;
|
|
jstr(resp,"access_token",access_token,at_cap);
|
|
if(refresh_out) jstr(resp,"refresh_token",refresh_out,rt_cap);
|
|
long exp=jnum(resp,"expires_in");
|
|
if(expires_out_epoch)*expires_out_epoch=time(NULL)+exp;
|
|
log_msg("oauth status=%d at=%s exp=%lds",status,access_token,(long)exp);
|
|
rc = (status==200 && access_token && *access_token) ? 0 : status;
|
|
done:
|
|
if(req>0)sceHttpDeleteRequest(req);
|
|
if(conn>0)sceHttpDeleteConnection(conn);
|
|
if(tpl>0)sceHttpDeleteTemplate(tpl);
|
|
return rc;
|
|
}
|
|
|
|
int http_get(const char *url,char *out,size_t cap){
|
|
if(http_init()) return -10;
|
|
int32_t tpl=0,conn=0,req=0,rc=0;
|
|
tpl=sceHttpCreateTemplate(s_http_ctx,"PS4RP/1.0",ORBIS_HTTP_VERSION_1_1,0); if(tpl<0)return -1;
|
|
conn=sceHttpCreateConnectionWithURL(tpl,url,0); if(conn<0){rc=-2;goto done;}
|
|
req=sceHttpCreateRequestWithURL(conn,ORBIS_METHOD_GET,url,0); if(req<0){rc=-3;goto done;}
|
|
sceHttpAddRequestHeader(req,"User-Agent","PS4RP/1.0",0);
|
|
if((rc=sceHttpSendRequest(req,0,0))<0){rc=-4;goto done;}
|
|
int total=0,len;
|
|
while((len=sceHttpReadData(req,out+total,cap-1-total))>0){total+=len; if(total>(int)cap-1)break;}
|
|
out[total>= (int)cap? (int)cap-1:total]=0;
|
|
rc=0;
|
|
done:
|
|
if(req>0)sceHttpDeleteRequest(req);
|
|
if(conn>0)sceHttpDeleteConnection(conn);
|
|
if(tpl>0)sceHttpDeleteTemplate(tpl);
|
|
return rc;
|
|
}
|