Skip to content

Instantly share code, notes, and snippets.

@ariankordi
Created December 26, 2019 04:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ariankordi/abbf647f9696bdfdc895a80a9d558444 to your computer and use it in GitHub Desktop.
Save ariankordi/abbf647f9696bdfdc895a80a9d558444 to your computer and use it in GitHub Desktop.
olvclient. this is stupid and dumb. i've had this on my github profile for 2 years and i've always been ashamed of this. it's literally useless by now and it's served little purpose being on my github page being that it's not a fully featured thicc project and stuff. i know i have like unfinished projects and stuf but they're stuff and they're l…
<?php
/*
OlvClient by Arian Kordi
https://github.com/ariankordi
Licensed under GNU AGPLv3: https://choosealicense.com/licenses/agpl-3.0/
*/
class OlvClient {
var $service_token;
var $param_pack;
var $clientkey;
var $clientkey_pass;
var $api_host;
var $olv_host;
/** new olvClient('/etc/certificates/client_certificate_that_doesnt_need_password.pem');
* OR... new olvClient('/etc/certificates/client_certificate_that_needs_password.p12', 'alpine');
*/
public function __construct($key, $pass = null) {
$this->clientkey = $key;
$this->clientkey_pass = $pass;
}
/**
* olvClient->setParamPack(array('title_id'=>'title id here', 'platform_id'=>platformid, 'language_id'=>lang, 'country_id'=>country, 'region_id'=>region));
*/
public function setParamPack(array $params = array()) {
/** Default:
* New Super Mario Bros. U, Wii U, English, USA, US
*/
$this->param_pack = base64_encode('\\title_id\\' . (isset($params['title_id']) ? hexdec($params['title_id']) : 1407375153044736) . '\\platform_id\\' . (isset($params['platform_id']) ? $params['platform_id'] : 1) . '\\region_id\\' . (isset($params['region_id']) ? $params['region_id'] : 2) . '\\language_id\\' . (isset($params['language_id']) ? $params['language_id'] : 1) . '\\country_id\\' . (isset($params['country_id']) ? $params['country_id'] : 49) . '\area_id\\0\\network_restriction\\0\\friend_restriction\\0\\rating_restriction\\20\\rating_organization\\0\\transferable_id\\0\\tz_name\\America/New_York\\utc_offset\\-18000\\');
}
/** Requires valid service token from NNAS, client ID 87cd32617f1985439ea608c2746e4610
* olvClient->setServiceToken('token');
*/
public function setServiceToken(string $service_token) {
$this->service_token = $service_token;
}
/** olvClient->('https://' . $this->api_host . '/v1/topics', false); (GET)
* OR... olvClient->('https://' . $this->olv_host . '/posts', 'body=aaa&feeling_id=0&is_spoiler=0'); (POST)
*/
private function olvRequest(string $url, array $post = null) {
if(empty($this->clientkey)) {
throw new Exception('No client key');
} elseif(empty($this->param_pack)) {
throw new Exception('Cannot authenticate');
}
$ch = curl_init();
$curl_array = array(
CURLOPT_URL => $url, CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_SSLCERT => $this->clientkey, CURLOPT_SSLCERTPASSWD => $this->clientkey_pass,
CURLOPT_USERAGENT => '3DS/POLV-3.0.1/FFFFF',
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => array('X-Nintendo-ParamPack: '.$this->param_pack,'X-Nintendo-ServiceToken: '.$this->service_token),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION=> false,);
if($post !== null) {
$curl_array[CURLOPT_POST] = true;
$curl_array[CURLOPT_POSTFIELDS] = $post;
}
curl_setopt_array($ch, $curl_array);
$response = curl_exec($ch);
$response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$content_type = strpos(curl_getinfo($ch, CURLINFO_CONTENT_TYPE), 'charset') !== false ? substr(curl_getinfo($ch, CURLINFO_CONTENT_TYPE),0,-15) : curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$body = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE));
if($response_code != 200) {
if(substr($body,0,25) == "<html>\n<head><title>400 N") {
throw new Exception('Bad client key');
}
elseif($response_code == 302) {
preg_match_all('/^Location:(.*)$/mi', $response, $matches);
return trim($matches[1][0]);
}
elseif($response_code == 500) {
return false;
}
}
if($content_type == 'application/xml') {
// parse xml if we are dealing with such
$xml = new SimpleXMLElement($body);
if(isset($xml->error_code) && $xml->error_code == 101) {
throw new Exception('Failed to authenticate');
}
return $xml;
}
elseif($content_type == 'application/json') {
// also parse json if we are doing that
return json_decode($body);
}
// if none of the above is satisfied (return ends the function), then return body
return $body;
}
/**
* olvClient->discoveryGetHosts()
*/
public function discoveryGetHosts() {
$req = $this->olvRequest('https://discovery.olv.nintendo.net/v1/endpoint');
return $req->endpoint;
}
/**
* setHosts(array('api_host'=>'api host', 'host'=>'host'));
*/
public function setHosts(array $hosts) {
if(isset($hosts['api_host'])) {
$this->api_host = $hosts['api_host'];
}
if(isset($hosts['olv_host'])) {
$this->olv_host = $hosts['olv_host'];
}
}
/**
* activateAccount(); to activate the service token
*/
public function activateAccount() {
return $this->olvRequest('https://' . $this->olv_host . '/welcome/activate?update_with_default=0', '');
}
public function getTopics() {
$req = $this->olvRequest('https://' . $this->api_host . '/v1/topics');
return $req;
}
/**
* olvClient->communityGetPosts(285, array('has_mii' => 1));
*/
public function communityGetPosts(int $community_id, array $param) {
$param['is_delay'] = 0;
$param['base_time'] = date('Y-m-d H:i:s', (!isset($param['base_time']) ? time() : $param['base_time']));
$req = $this->olvRequest('https://' . $this->api_host . '/v1/communities/' . $community_id . '/posts?' . http_build_query($param));
return $req->posts;
}
public function communityGetIndividualTopic(int $community_id, array $param) {
$param['is_delay'] = 0;
$param['base_time'] = date('Y-m-d H:i:s', (!isset($param['base_time']) ? time() : $param['base_time']));
$req = $this->olvRequest('https://' . $this->api_host . '/v1/communities/' . $community_id . '?' . http_build_query($param));
return $req->posts;
}
/**
* pidToUserID(1799999999);
*/
public function pidToUserID(int $pid) {
$req = $this->olvRequest('https://' . $this->olv_host . '/users/show?pid=' . $pid);
return substr($req,strlen('https://' . $this->olv_host . '/users/'));
}
/** personFollow('chris4403t1'); follow
* personFollow('NintendoTom', false); unfollow
*/
public function personFollow(string $user_id) {
$req = $this->olvRequest('https://' . $this->olv_host . '/users/' . $user_id . '.' . (func_num_args() == 2 ? 'un' : '') . 'follow.json', '');
return $req;
}
public function decodeMii($mii) {
$mii = base64_decode($mii);
return array(
'sex'=> substr(strrev(decbin(hexdec(unpack('H*', substr($mii,24,1))[1]))),0,1) == 1 ? 1 : 0,
'height' => unpack('c*', substr($mii,46,1)),
'weight' => unpack('c*', substr($mii,47,1)),
'hair' => unpack('c*', substr($mii,50,1)),
);
}
public function postCreate(array $param) {
if(!isset($param['feeling_id'])) {
$param['feeling_id'] = 0;
}
if(!isset($param['_post_type'])) {
$param['_post_type'] = 'body';
}
$req = $this->olvRequest('https://' . $this->api_host . '/v1/posts', http_build_query($param));
return $req;
}
public function postView(string $post) {
$req = $this->olvRequest('https://' . $this->api_host . '/v1/posts/' . $post . '?' . (func_num_args() == 2 ? http_build_query(func_get_args[1]) : ''));
return $req;
}
public function postEmpathy(string $post) {
$req = $this->olvRequest('https://' . $this->api_host . '/v1/posts/' . $post . '/empathies' . (func_num_args() == 2 ? '.delete' : ''), '');
return $req;
}
public function postReply(string $post, array $param) {
if(!isset($param['feeling_id'])) {
$param['feeling_id'] = 0;
}
if(!isset($param['_post_type'])) {
$param['_post_type'] = 'body';
}
$req = $this->olvRequest('https://' . $this->api_host . '/v1/posts/' . $post . '/replies', http_build_query($param));
return $req;
}
}
@ariankordi
Copy link
Author

here is the readme

OlvClient

A PHP class for interfacing with Nintendo's Miiverse (olv) servers.

Wait, what?

Miiverse has had an API for some time. It's not documented except for on Nintendo's dev servers themselves. I've built a class to be used for very basic communicating with the API along with other clients.

Why?

I'm considering this to be the coup de grace to Miiverse hax since this is pretty much the most you can go, the API. Also, how cool would it be to post to Miiverse in something? The API isn't publicly documented yet but will be once I'm done with this completely.

Notice

I don't know very much PHP, and there are a lot of to-dos here, so don't rely on this or anything.
Again, this is very very basic, you can't do much with this (yet).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment