닌텐도 스위치 REST API 소개
개술
커뮤니티의 노력 덕분에 우리는 프로그래밍 방식으로 닌텐도 스위치의 API를 제로비용으로 방문할 수 있었다.이를 통해 우리는 닌텐도 온라인 스위치(NSO)에 연결된 게임과 통신하고 게임과 같은 사용자 정보를 얻을 수 있는 프로그램을 구축할 수 있다.
API 요청에 메시지를 입력하거나 동물 교차 반응을 사용하십시오!
API 액세스
1. 닌텐도 회화 영패
누군가가 닌텐도에 로그인한 특수 권한 수여 링크가 있을 때, 닌텐도는 브라우저를 세션 영패를 포함하는 URL로 바꿉니다.
이 링크를 만들기 위해서 베이스64url 형식에 S256 코드 도전을 포함해야 합니다.지금 모르면what this means 걱정하지 마세요.간단하게 말하자면, 우리는 키의 산열 값을 닌텐도에 건네주고, 이따가 원시 키로 우리가 로그인한 사람이 같다는 것을 증명할 것이다.
$npm install base64url, request-promise-native, uuid
const crypto = require('crypto');
const base64url = require('base64url');
let authParams = {};
function generateRandom(length) {
return base64url(crypto.randomBytes(length));
}
function calculateChallenge(codeVerifier) {
const hash = crypto.createHash('sha256');
hash.update(codeVerifier);
const codeChallenge = base64url(hash.digest());
return codeChallenge;
}
function generateAuthenticationParams() {
const state = generateRandom(36);
const codeVerifier = generateRandom(32);
const codeChallenge = calculateChallenge(codeVerifier);
return {
state,
codeVerifier,
codeChallenge
};
}
function getNSOLogin() {
authParams = generateAuthenticationParams();
const params = {
state: authParams.state,
redirect_uri: 'npf71b963c1b7b6d119://auth&client_id=71b963c1b7b6d119',
scope: 'openid%20user%20user.birthday%20user.mii%20user.screenName',
response_type: 'session_token_code',
session_token_code_challenge: authParams.codeChallenge,
session_token_code_challenge_method: 'S256',
theme: 'login_form'
};
const arrayParams = [];
for (var key in params) {
if (!params.hasOwnProperty(key)) continue;
arrayParams.push(`${key}=${params[key]}`);
}
const stringParams = arrayParams.join('&');
return `https://accounts.nintendo.com/connect/1.0.0/authorize?${stringParams}`;
}
const loginURL = getNSOLogin();
console.log(loginURL);
Beginner's Tip: type the following commands to quickly run JavaScript on your Terminal:
$touch myApp.js
to create the file.$nano myApp.js
to modify the contents.$node myApp.js
to run the program.
다음과 같은 URL을 입력해야 합니다.
https://accounts.nintendo.com/connect/1.0.0/authorize?state=[SessionStateReturnedHere]&redirect_uri=npf71b963c1b7b6d119://auth...
브라우저의 URL에 액세스하여 닌텐도 계정에 로그인합니다.이 페이지로 안내됩니다.이 계정을 선택하려면 오른쪽 단추를 누르고 리셋 링크를 복사하십시오.다음 형식이 적용됩니다.
npf71b963c1b7b6d119://auth#session_state=[SessionStateReturned]&session_token_code=[SessionTokenCodeReturned]&state=[StateReturned]
일반적인 HTTP나 HTTPS 프로토콜과 달리 링크를 되돌려 주는 프로토콜은 npf71b963c1b7b6d119입니다. 이것은 브라우저를 간단하게 누르고 방향을 바꿀 수 없는 이유입니다.To build an app for this, we can either have the user right click -> copy and tell us their redirect url, or we could subscribe to the npf protocol and automatically redirect the user back to our app.
그리고 이 리셋 URL에서 세션 카드 코드를 추출할 수 있습니다.
const params = {};
redirectURL.split('#')[1]
.split('&')
.forEach(str => {
const splitStr = str.split('=');
params[splitStr[0]] = splitStr[1];
});
// the sessionTokenCode is params.session_token_code
세션 토큰 코드를 통해 우리는 닌텐도에 닌텐도 세션 토큰을 요청할 수 있다.At the time of this writing, the NSO app version is 1.9.0, which changes around 1~2 times a year. Check this repo for updates.
const request2 = require('request-promise-native');
const jar = request2.jar();
const request = request2.defaults({ jar: jar });
const userAgentVersion = `1.9.0`; // version of Nintendo Switch App, updated once or twice per year
async function getSessionToken(session_token_code, codeVerifier) {
const resp = await request({
method: 'POST',
uri: 'https://accounts.nintendo.com/connect/1.0.0/api/session_token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': `OnlineLounge/${userAgentVersion} NASDKAPI Android`
},
form: {
client_id: '71b963c1b7b6d119',
session_token_code: session_token_code,
session_token_code_verifier: codeVerifier
},
json: true
});
return resp.session_token;
}
2. 웹 서비스 토큰
웹 서비스 토큰을 받으려면 다음과 같이 하십시오.
I. 세션 토큰을 사용하여 API 토큰 가져오기
둘API 토큰을 사용하여 사용자 정보 얻기
3. f 로고를 획득[NSO]
4. f 플래그 [NSO] 및 사용자 정보가 포함된 API 액세스 토큰 얻기
V. API 액세스 토큰을 사용하여 f 플래그 [App] 가져오기
6. API 액세스 토큰과 f 로고를 사용하여 웹 서비스 토큰을 획득[App]
이것은 사람들로 하여금 두려워하게 할 수도 있지만, 실현 중에는 일련의 비동기 서버 요청만 있을 뿐이다.
const { v4: uuidv4 } = require('uuid');
async function getWebServiceTokenWithSessionToken(sessionToken, game) {
const apiTokens = await getApiToken(sessionToken); // I. Get API Token
const userInfo = await getUserInfo(apiTokens.access); // II. Get userInfo
const guid = uuidv4();
const timestamp = String(Math.floor(Date.now() / 1000));
const flapg_nso = await callFlapg(apiTokens.id, guid, timestamp, "nso"); // III. Get F flag [NSO]
const apiAccessToken = await getApiLogin(userInfo, flapg_nso); // IV. Get API Access Token
const flapg_app = await callFlapg(apiAccessToken, guid, timestamp, "app"); // V. Get F flag [App]
const web_service_token = await getWebServiceToken(apiAccessToken, flapg_app, game); // VI. Get Web Service Token
return web_service_token;
}
이제 이 요청들을 실현해 주십시오.const userAgentString = `com.nintendo.znca/${userAgentVersion} (Android/7.1.2)`;
async function getApiToken(session_token) {
const resp = await request({
method: 'POST',
uri: 'https://accounts.nintendo.com/connect/1.0.0/api/token',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': userAgentString
},
json: {
client_id: '71b963c1b7b6d119',
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer-session-token',
session_token: session_token
}
});
return {
id: resp.id_token,
access: resp.access_token
};
}
async function getHash(idToken, timestamp) {
const response = await request({
method: 'POST',
uri: 'https://elifessler.com/s2s/api/gen2',
headers: {
'User-Agent': `yournamehere` // your unique id here
},
form: {
naIdToken: idToken,
timestamp: timestamp
}
});
const responseObject = JSON.parse(response);
return responseObject.hash;
}
async function callFlapg(idToken, guid, timestamp, login) {
const hash = await getHash(idToken, timestamp)
const response = await request({
method: 'GET',
uri: 'https://flapg.com/ika2/api/login?public',
headers: {
'x-token': idToken,
'x-time': timestamp,
'x-guid': guid,
'x-hash': hash,
'x-ver': '3',
'x-iid': login
}
});
const responseObject = JSON.parse(response);
return responseObject.result;
}
async function getUserInfo(token) {
const response = await request({
method: 'GET',
uri: 'https://api.accounts.nintendo.com/2.0.0/users/me',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': userAgentString,
Authorization: `Bearer ${token}`
},
json: true
});
return {
nickname: response.nickname,
language: response.language,
birthday: response.birthday,
country: response.country
};
}
async function getApiLogin(userinfo, flapg_nso) {
const resp = await request({
method: 'POST',
uri: 'https://api-lp1.znc.srv.nintendo.net/v1/Account/Login',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': userAgentString,
Authorization: 'Bearer'
},
body: {
parameter: {
language: userinfo.language,
naCountry: userinfo.country,
naBirthday: userinfo.birthday,
f: flapg_nso.f,
naIdToken: flapg_nso.p1,
timestamp: flapg_nso.p2,
requestId: flapg_nso.p3
}
},
json: true,
gzip: true
});
return resp.result.webApiServerCredential.accessToken;
}
async function getWebServiceToken(token, flapg_app, game) {
let parameterId;
if (game == 'S2') {
parameterId = 5741031244955648; // SplatNet 2 ID
} else if (game == 'AC') {
parameterId = 4953919198265344; // Animal Crossing ID
}
const resp = await request({
method: 'POST',
uri: 'https://api-lp1.znc.srv.nintendo.net/v2/Game/GetWebServiceToken',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': userAgentString,
Authorization: `Bearer ${token}`
},
json: {
parameter: {
id: parameterId,
f: flapg_app.f,
registrationToken: flapg_app.p1,
timestamp: flapg_app.p2,
requestId: flapg_app.p3
}
}
});
return {
accessToken: resp.result.accessToken,
expiresAt: Math.round(new Date().getTime()) + resp.result.expiresIn
};
}
이제 함수를 호출하여 웹 서비스 토큰을 가져옵니다.(async () => {
const sessionToken = await getSessionToken(params.session_token_code, authParams.codeVerifier);
const webServiceToken = await getWebServiceTokenWithSessionToken(sessionToken, game='S2');
console.log('Web Service Token', webServiceToken);
})()
이것이 바로 되돌아오는 웹 서비스 영패의 외관이다.성공을 축하합니다!이제 닌텐도 API의 즐거움이 시작된다:)
Splaton 2의 SplatNet 액세스
SplatNet(Splaton 2)에 액세스하기 위해 웹 서비스 토큰을 사용하여iksm 세션이라는 쿠키를 가져옵니다.
(async () => {
const sessionToken = await getSessionToken(params.session_token_code, authParams.codeVerifier);
const webServiceToken = await getWebServiceTokenWithSessionToken(sessionToken, game='S2');
await getSessionCookieForSplatNet(webServiceToken.accessToken);
const iksmToken = getIksmToken();
console.log('iksm_token', iksmToken);
})()
const splatNetUrl = 'https://app.splatoon2.nintendo.net';
async function getSessionCookieForSplatNet(accessToken) {
const resp = await request({
method: 'GET',
uri: splatNetUrl,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Platform': 'Android',
'X-ProductVersion': userAgentVersion,
'User-Agent': userAgentString,
'x-gamewebtoken': accessToken,
'x-isappanalyticsoptedin': false,
'X-Requested-With': 'com.nintendo.znca',
Connection: 'keep-alive'
}
});
const iksmToken = getIksmToken();
}
function getCookie(key, url) {
const cookies = jar.getCookies(url);
let value;
cookies.find(cookie => {
if (cookie.key === key) {
value = cookie.value;
}
return cookie.key === key;
});
return value;
}
function getIksmToken() {
iksm_session = getCookie('iksm_session', splatNetUrl);
if (iksm_session == null) {
throw new Error('Could not get iksm_session cookie');
}
return iksm_session
}
이 쿠키가 있으면 iksm 세션 쿠키를 수정하여 브라우저에 직접 접근할 수 있습니다SplatNet.Beginner's Tip: To modify cookies on Chrome, press F12 for Developer Tools -> Applications Tab -> Storage. You can edit, add, and remove cookies there.
SplatNet을 탐색할 때 개발자 도구의 네트워크 탭을 모니터링하고 호출된 API를 볼 수 있습니다.
그런 다음 이러한 API를 응용 프로그램에 사용할 수 있습니다.웹 영패를 사용하여 요청을 보내면 쿠키는 요청 대상으로 설정됩니다.
const userLanguage = 'en-US';
(async () => {
..
const iksmToken = getIksmToken();
const records = await getSplatnetApi('records');
console.log('records', records);
async function getSplatnetApi(url) {
const resp = await request({
method: 'GET',
uri: `${splatNetUrl}/api/${url}`,
headers: {
Accept: '*/*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': userLanguage,
'User-Agent': userAgentString,
Connection: 'keep-alive'
},
json: true,
gzip: true
});
return resp;
}
다음은 records API 끝점을 실행한 결과입니다.공통 SplatNet 끝점
/결과는 최근 50회 일치를 나타냅니다.
/coop 의 결과는 최근 50차례의 연어 경기를 나타냈다.
/시간표에 곧 다가올 교대가 표시되어 있다.
/coop 시간표는 곧 다가올 연어의 교대를 나타낸다.
/x power ranking/201101T00 201201201T00/summary는 현재 차트에서 최고 x 출력과 현재 x 출력을 표시합니다.
동물 통로 진입
Animal Crossing에 액세스하려면 먼저 Animal Crossing의 웹 서비스 토큰을 받아야 합니다.
(async () => {
const sessionToken = await getSessionToken(params.session_token_code, authParams.codeVerifier);
const webServiceToken = await getWebServiceTokenWithSessionToken(sessionToken, game='AC');
const acTokens = await getCookiesForAnimalCrossing(webServiceToken.accessToken);
우리가 동물 횡단 노드를 방문하면 웹 서비스 영패는 gtoken으로 저장됩니다.이 쿠키는 park session이라는 다른 쿠키의 사용자 API와 인증 로드 토큰을 액세스하기 위해 필요합니다.const ACUrl = 'https://web.sd.lp1.acbaa.srv.nintendo.net';
let ACBearerToken;
let ACHeaders = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'gzip,deflate',
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': userAgentString,
'x-isappanalyticsoptedin': false,
'X-Requested-With': 'com.nintendo.znca',
'DNT': '0',
Connection: 'keep-alive'
}
async function getCookiesForAnimalCrossing(accessToken) {
const resp = await request({
method: 'GET',
uri: ACUrl,
headers: Object.assign(ACHeaders, {'X-GameWebToken': accessToken}),
});
const animalCrossingTokens = await getAnimalCrossingTokens();
return animalCrossingTokens;
}
async function getAnimalCrossingTokens() {
const gToken = getCookie('_gtoken', ACUrl)
if (gToken == null) {
throw new Error('Could not get _gtoken for Animal Crossing');
}
jar.setCookie(request2.cookie(`_gtoken=${gToken}`), ACUrl);
const userResp = await request({
method: 'GET',
uri: `${ACUrl}/api/sd/v1/users`,
headers: ACHeaders,
json: true
});
if (userResp !== null) {
const userResp2 = await request({
method: 'POST',
uri: `${ACUrl}/api/sd/v1/auth_token`,
headers: ACHeaders,
form: {
userId: userResp['users'][0]['id']
},
json: true
});
const bearer = userResp2;
const parkSession = getCookie('_park_session', ACUrl);
if (parkSession == null) {
throw new Error('Could not get _park_session for Animal Crossing');
}
if (bearer == null || !bearer['token']) {
throw new Error('Could not get bearer for Animal Crossing');
}
ACBearerToken = bearer['token']; // Used for Authorization Bearer in Header
return {
ac_g: gToken,
ac_p: parkSession
}
}
}
이제 우리는 동물이 횡단하는 API를 호출할 수 있다!Note: Not all of Animal Crossing's API requires the Bearer Token and the _park_session cookie. If the string "users" are a part of the request url, for example /api/sd/v1/users, we only need to provide the _g_token.
다음은/sd/v1/friends 단점의 결과입니다. 이 단점은 당신의 가장 친한 친구를 열거합니다.
(async () => {
..
const acTokens = await getCookiesForAnimalCrossing(webServiceToken.accessToken);
const bestFriends = await getAnimalCrossingApi('sd/v1/friends');
console.log('Best Friends', bestFriends);
})()
async function getAnimalCrossingApi(url) {
const resp = await request({
method: 'GET',
uri: `${ACUrl}/api/${url}`,
headers: Object.assign(ACHeaders, { Authorization: `Bearer ${ACBearerToken}`}),
json: true,
gzip: true
});
return resp;
}
흔한 동물 교차 종점
/sd/v1/users는 사용자 이름, 섬, 여권 사진을 표시합니다.
/sd/v1/users/:user_id/profile?language=en US는 사용자의 여권을 표시합니다.
/sd/v1/lands/:land id/profile 섬 데이터를 표시합니다.
/sd/v1/friends는 가장 친한 친구와 정보를 열거합니다.
/게임에서 sd/v1 반응이 있는 메시지를 보냅니다.
{
"body": "Sweet",
"type": "keyboard"
}
반응 요청을 전송한 후 메커니즘:
{
"body": "Aha",
"type": "emoticon"
}
List of Reaction Values
토큰과 과자 리셋
일단 웹 서비스 영패가 만료되면, 우리는 우리의 초기 닌텐도 세션 영패를 사용하여 새로운 영패를 얻을 수 있다.일반적으로 다시 로그인할 필요가 없습니다.
요약
샘플 항목
Splatnet/Music Bot: 디스코트 로봇으로 사용자가 동물이 여권과 splaton 2등급을 통과할 수 있도록 한다.
Squid Tracks: Splation2의 모든 기능을 갖춘 데스크탑 클라이언트나는 최근에 이 응용 프로그램의 인증 논리를 업데이트해서 다시 실행하도록 도와주었다.
Splatnet Desktop: 간단한 전자 응용 프로그램을 작성하여 간단한 신분 검증을 통해 데스크톱의 SplatNet에 접근했습니다.
Splatoon2.Ink: 현재 Splaton 2단계 웹 사이트를 표시합니다.
Streaming Widget: Splation2 일치 결과를 표시하는 작은 위젯입니다.
Nightbot을 Splaton 2의 SplatNet에 연결하는 방법 | 작성자: Mathew Chan | Medium
진 매튜・ 2021년 1월 31일・ yui-spl2。중등
필기
도구책
Nintendo Switch REST API
Reference
이 문제에 관하여(닌텐도 스위치 REST API 소개), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mathewthe2/intro-to-nintendo-switch-rest-api-2cm7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)