implement /infodesk endpoints

This commit is contained in:
Andrew Glaze
2025-05-15 18:29:54 -04:00
parent a94752a799
commit 04c5660f7d
8 changed files with 686 additions and 41 deletions

5
.gitignore vendored
View File

@@ -8,4 +8,7 @@ db.sqlite
.swiftpm
.env
.env.*
!.env.example
!.env.example
cdn/
__pycache__/

285
Package.resolved Normal file
View File

@@ -0,0 +1,285 @@
{
"originHash" : "d53dfe2770a8b5d4063e71737e72637f59cec754bf4553178a66d10f39bfb1ee",
"pins" : [
{
"identity" : "async-http-client",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swift-server/async-http-client.git",
"state" : {
"revision" : "3b265e6a00fc5c3fdb8f91f773e506990c704337",
"version" : "1.26.0"
}
},
{
"identity" : "async-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/async-kit.git",
"state" : {
"revision" : "e048c8ee94967e8d8a1c2ec0e1156d6f7fa34d31",
"version" : "1.20.0"
}
},
{
"identity" : "console-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/console-kit.git",
"state" : {
"revision" : "742f624a998cba2a9e653d9b1e91ad3f3a5dff6b",
"version" : "4.15.2"
}
},
{
"identity" : "fluent",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/fluent.git",
"state" : {
"revision" : "223b27d04ab2b51c25503c9922eecbcdf6c12f89",
"version" : "4.12.0"
}
},
{
"identity" : "fluent-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/fluent-kit.git",
"state" : {
"revision" : "8baacd7e8f7ebf68886c496b43bbe6cdcc5b57e0",
"version" : "1.52.2"
}
},
{
"identity" : "fluent-sqlite-driver",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/fluent-sqlite-driver.git",
"state" : {
"revision" : "73529a63ab11c7fe87da17b5a67a1b1f58c020f8",
"version" : "4.8.1"
}
},
{
"identity" : "multipart-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/multipart-kit.git",
"state" : {
"revision" : "3498e60218e6003894ff95192d756e238c01f44e",
"version" : "4.7.1"
}
},
{
"identity" : "routing-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/routing-kit.git",
"state" : {
"revision" : "93f7222c8e195cbad39fafb5a0e4cc85a8def7ea",
"version" : "4.9.2"
}
},
{
"identity" : "sql-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/sql-kit.git",
"state" : {
"revision" : "baf0d8684a43f16cd11ebcc67300c8ab5cb5d078",
"version" : "3.33.0"
}
},
{
"identity" : "sqlite-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/sqlite-kit.git",
"state" : {
"revision" : "f35a863ecc2da5d563b836a9a696b148b0f4169f",
"version" : "4.5.2"
}
},
{
"identity" : "sqlite-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/sqlite-nio.git",
"state" : {
"revision" : "fe1257499440de396504eea2b7793ce1f984c324",
"version" : "1.11.3"
}
},
{
"identity" : "swift-algorithms",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-algorithms.git",
"state" : {
"revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023",
"version" : "1.2.1"
}
},
{
"identity" : "swift-asn1",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-asn1.git",
"state" : {
"revision" : "a54383ada6cecde007d374f58f864e29370ba5c3",
"version" : "1.3.2"
}
},
{
"identity" : "swift-atomics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
"version" : "1.1.4"
}
},
{
"identity" : "swift-crypto",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-crypto.git",
"state" : {
"revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed",
"version" : "3.12.3"
}
},
{
"identity" : "swift-distributed-tracing",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-distributed-tracing.git",
"state" : {
"revision" : "a64a0abc2530f767af15dd88dda7f64d5f1ff9de",
"version" : "1.2.0"
}
},
{
"identity" : "swift-http-structured-headers",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-http-structured-headers.git",
"state" : {
"revision" : "db6eea3692638a65e2124990155cd220c2915903",
"version" : "1.3.0"
}
},
{
"identity" : "swift-http-types",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-http-types.git",
"state" : {
"revision" : "a0a57e949a8903563aba4615869310c0ebf14c03",
"version" : "1.4.0"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa",
"version" : "1.6.3"
}
},
{
"identity" : "swift-metrics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-metrics.git",
"state" : {
"revision" : "4c83e1cdf4ba538ef6e43a9bbd0bcc33a0ca46e3",
"version" : "2.7.0"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "34d486b01cd891297ac615e40d5999536a1e138d",
"version" : "2.83.0"
}
},
{
"identity" : "swift-nio-extras",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-extras.git",
"state" : {
"revision" : "f1f6f772198bee35d99dd145f1513d8581a54f2c",
"version" : "1.26.0"
}
},
{
"identity" : "swift-nio-http2",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-http2.git",
"state" : {
"revision" : "4281466512f63d1bd530e33f4aa6993ee7864be0",
"version" : "1.36.0"
}
},
{
"identity" : "swift-nio-ssl",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-ssl.git",
"state" : {
"revision" : "4b38f35946d00d8f6176fe58f96d83aba64b36c7",
"version" : "2.31.0"
}
},
{
"identity" : "swift-nio-transport-services",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-transport-services.git",
"state" : {
"revision" : "cd1e89816d345d2523b11c55654570acd5cd4c56",
"version" : "1.24.0"
}
},
{
"identity" : "swift-numerics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-numerics.git",
"state" : {
"revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8",
"version" : "1.0.3"
}
},
{
"identity" : "swift-service-context",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-service-context.git",
"state" : {
"revision" : "8946c930cae601452149e45d31d8ddfac973c3c7",
"version" : "1.2.0"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1",
"version" : "1.4.2"
}
},
{
"identity" : "vapor",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/vapor.git",
"state" : {
"revision" : "87b0edd2633c35de543cb7573efe5fbf456181bc",
"version" : "4.114.1"
}
},
{
"identity" : "websocket-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/websocket-kit.git",
"state" : {
"revision" : "8666c92dbbb3c8eefc8008c9c8dcf50bfd302167",
"version" : "2.16.1"
}
}
],
"version" : 3
}

View File

@@ -0,0 +1,188 @@
import Fluent
import Vapor
struct InfodeskController: RouteCollection {
func boot(routes: any RoutesBuilder) throws {
let group = routes.grouped("infodesk", "v2")
group.get("appGroup", use: self.appGroup)
group.get("app", use: self.app)
}
@Sendable
func appGroup(req: Request) async throws -> Response {
var headers = HTTPHeaders()
headers.add(name: "sig", value: "0;F8rysQxii/VL6Rca6Gnw/lq1AXA0N1RfAkKHosaiYWM=")
return Response(status: .ok, headers: headers, body: .init(string: """
{
"status": 200,
"desc": "OK",
"content": {
"timestamp": 1717794472083,
"apps": [
{
"notices": [],
"appId": "535877",
"dataMap": {
"countryCodes": "kr",
"countryCodeList": "kr",
"displayName": "\u{c6d4}\u{b4dc} \u{d50c}\u{b9ac}\u{d37c}",
"forceServerSelectDeviceList": "iPad6,4 iPad7,2 iPad7,4 iPad13,6",
"bannedCountryCodeList": "-",
"isServiceAvailable": "true"
}
},
{
"notices": [],
"appId": "561429",
"dataMap": {
"countryCodes": "us",
"countryCodeList": "ag,ai,an,ar,aw,bb,bl,bm,bo,bq,br,bs,bz,ca,cl,co,cr,cu,cw,dm,do,ec,fk,gd,gf,gp,gs,gt,gy,hn,ht,jm,kn,ky,lc,mf,mq,ms,mx,ni,pa,pe,pm,pr,py,sr,sv,sx,tc,tt,um,us,uy,vc,ve,vg,vi",
"displayName": "World Flipper (NA)",
"forceServerSelectDeviceList": "iPad6,4 iPad7,2 iPad7,4 iPad13,6",
"bannedCountryCodeList": "-",
"isServiceAvailable": "true"
}
},
{
"notices": [],
"appId": "561430",
"dataMap": {
"countryCodes": "de",
"countryCodeList": "ad,ae,al,am,ao,at,ax,az,ba,be,bf,bg,bh,bi,bj,bv,bw,by,cd,cf,cg,ch,ci,cm,cv,cy,cz,de,dj,dk,dz,ee,eg,eh,er,es,et,fi,fo,fr,ga,gb,ge,gg,gh,gi,gl,gm,gn,gq,gr,gw,hr,hu,ie,il,im,iq,ir,is,it,je,jo,ke,km,kw,lb,li,lr,ls,lt,lu,lv,ly,ma,mc,md,me,mg,mk,ml,mr,mt,mu,mw,mz,na,ne,ng,nl,no,om,pl,ps,pt,qa,re,ro,rs,ru,rw,sa,sc,sd,se,sh,si,sj,sk,sl,sm,sn,so,ss,st,sy,sz,td,tf,tg,tn,tr,tz,ua,ug,uz,va,ye,yt,za,zm,zw",
"displayName": "World Flipper (EU)",
"forceServerSelectDeviceList": "iPad6,4 iPad7,2 iPad7,4 iPad13,6",
"bannedCountryCodeList": "-",
"isServiceAvailable": "true"
}
},
{
"notices": [],
"appId": "561432",
"dataMap": {
"countryCodes": "th",
"countryCodeList": "af,as,au,bd,bn,bt,cc,ck,cx,fj,fm,gu,hm,id,in,io,kg,kh,ki,kz,la,lk,mh,mm,mn,mp,mv,my,nc,nf,np,nr,nu,nz,pf,pg,ph,pk,pn,pw,sb,sg,th,tj,tk,tl,tm,to,tv,vn,vu,wf,ws",
"displayName": "World Flipper (SEA)",
"forceServerSelectDeviceList": "iPad6,4 iPad7,2 iPad7,4 iPad13,6",
"bannedCountryCodeList": "-",
"isServiceAvailable": "true"
}
}
]
}
}
"""))
}
@Sendable
func app(req: Request) async throws -> Response {
var headers = HTTPHeaders()
headers.add(name: "sig", value: "0;F8rysQxii/VL6Rca6Gnw/lq1AXA0N1RfAkKHosaiYWM=")
return Response(status: .ok, headers: headers, body: .init(string: #"""
{
"status": 200,
"desc": "OK",
"content": {
"supportedFeatures": [
"urgentNotice",
"maintenance",
"push",
"delivery",
"promotion",
"coupon",
"notice"
],
"marketUrl": "market://details?id=com.kakaogames.wdfp",
"publicKeyMap": {},
"secondaryPwOption": null,
"capriAppOption": {
"ageLimit": 0,
"lazyAgeAuth": null,
"appType": "LEGACY_PARTNER",
"appCategory": "Games",
"ageAuthLevel": "NONE"
},
"isTubeApp": false,
"verRecent": "0.0.81",
"appOption": {
"urlCommunity": "https://twitter.com/Worldflipper_kg",
"urlOtherMenuOfficialCafe": "https://twitter.com/Worldflipper_kg",
"urlTitleMenuContact": "oqupie",
"cdnAddr": "http://patch.wdfp.kakaogames.com/Live/2.0.0",
"agreementUrl": "https://web-data-game.kakaocdn.net/real/www/html/agreement/index.html?tid=13",
"useCoupon": "true",
"useGoogleGame": "FALSE",
"urlPrivacyPolicy": "https://web-data-cdn.kakaogames.com/real/www/html/terms/index.html?service=S0001&type=T003",
"urlFriendFollowServer": "https://na.wdfp.kakaogames.com",
"useHttpHeartbeat": "true",
"isReproduceS3UploadOpen": "false",
"urlTermsAndConditions": "https://web-data-game.kakaocdn.net/real/www/html/terms/index.html?service=S0001&type=T001&country=us&lang=en",
"urlHomeNews": "https://worldflipper.playkakaogames.com/news",
"gameServerAddr": "https://na.wdfp.kakaogames.com",
"modTime": 1617070960617,
"urlTitleMenuNews": "https://worldflipper.playkakaogames.com/news",
"refreshInfodeskIntervalMin": "5",
"urlOtherMenuContact": "oqupie",
"urlNotice": "https://worldflipper.playkakaogames.com/news",
"urlReviewContact": "https://kakaogames.oqupie.com/portals/2060"
},
"notices": [],
"traceSampleRate": 0,
"isWhitelist": false,
"svcStatus": "open",
"supportedIdpCodes": [
"facebook",
"google",
"siwa",
"zd3"
],
"serverConnectionType": "https",
"appVerStatus": "noNeedToUpdate",
"publisher": {
"privacyUrl": "https://www.kakao.com/ko/privacy",
"privacySummaryUrl": "https://gameevent.kakao.com/supports/terms/3?tabbar=false",
"noticeUrl2": "https://cus-zinny3.kakaogames.com/view/notice",
"agreementUrl": "https://web-data-game.kakaocdn.net/real/www/html/agreement/index.html?tid=13",
"servicePolicyUrl": "https://gameevent.kakao.com/terms/operation",
"termsUrl": "https://gameevent.kakao.com/supports/terms/1",
"kakaogameCommunityUrl": "https://playgame.kakao.com/bridge/auth/zinny",
"termsSummaryUrl": "https://gameevent.kakao.com/supports/terms/1?tabbar=false",
"eventWallUrl": "https://cus-zinny3.kakaogames.com/view/event",
"noticeUrl": "https://cus-zinny3.kakaogames.com/notice",
"customerServiceUrl": "https://cus-zinny3.kakaogames.com/support/list",
"eventWinnerUrl": "http://event-winner.kakaogames.com/event",
"policyVer": "1.0",
"publisherId": "kakao",
"modTime": 1651813742832
},
"sdk": {
"heartbeatInterval": 120000,
"PercentOfSendingAPICallLog": 0,
"stopSendGeoDNS": "y",
"snsShareUrl": "https://invite.kakaogame.com",
"zrtiOSError": "{\"kakaocapri\":[500, 502, 503, -1, -7, -9]}",
"aesEncryptKey": "djfdskj12328438djdgjcjeejhdew15",
"aesEncryptIV": "7gnfn7f96rnanmt1s5iaa3kdruhuneu",
"cafeLoginUrl": "https://accounts.kakao.com/weblogin/sso_login?token={tgt_token}&token_type=tgt&continue={url}",
"zrtAOSError": "{\"kakaocapri\":[500, 502, 503, -1, -7, -9],\"google\":[8]}",
"zrtWindowsError": "{\"kakaocapri\":[500, 502, 503, -1, -7, -9]}",
"snsShareHostUrl": "https://invite.kakaogame.com/host/main",
"invitationUrl": "https://webinvite.nzincorp.com",
"csUrl": "http://customer.kakaogames.com:18080",
"platformVersion": 3,
"sessionTimeout": 10000,
"registerDeviceUrl": "https://device-enrollment.kakaogames.com/main",
"customDialogModels": [
"SM-T976N"
],
"unregisterAgreementUrl": "https://web-data-cdn.kakaogames.com/real/www/html/terms/index.html?service=S0001&type=T016",
"snsShareGuestUrl": "https://invite.kakaogame.com/guest/reward"
},
"deviceSecurityOption": null,
"onlineNotifications": [],
"timestamp": 1717794472611
}
}
"""#))
}
}

View File

@@ -1,37 +0,0 @@
import Fluent
import Vapor
struct TodoController: RouteCollection {
func boot(routes: any RoutesBuilder) throws {
let todos = routes.grouped("todos")
todos.get(use: self.index)
todos.post(use: self.create)
todos.group(":todoID") { todo in
todo.delete(use: self.delete)
}
}
@Sendable
func index(req: Request) async throws -> [TodoDTO] {
try await Todo.query(on: req.db).all().map { $0.toDTO() }
}
@Sendable
func create(req: Request) async throws -> TodoDTO {
let todo = try req.content.decode(TodoDTO.self).toModel()
try await todo.save(on: req.db)
return todo.toDTO()
}
@Sendable
func delete(req: Request) async throws -> HTTPStatus {
guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else {
throw Abort(.notFound)
}
try await todo.delete(on: req.db)
return .noContent
}
}

View File

@@ -8,9 +8,11 @@ public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
app.databases.use(DatabaseConfigurationFactory.sqlite(.file("db.sqlite")), as: .sqlite)
app.databases.use(DatabaseConfigurationFactory.sqlite(.file("db.sqlite")), as: .sqlite)
app.migrations.add(CreateTodo())
app.http.server.configuration.hostname = "0.0.0.0"
app.http.server.configuration.port = 8000
// register routes
try routes(app)

View File

@@ -0,0 +1,140 @@
import Vapor
struct OpenApi {
func registerRoutes(_ app: Application) {
let group = app.grouped("openapi", "service")
group.post("v3", "util", "country", "get") { req async -> String in
"{\"country\": \"us\"}"
}
group.post("v4", "device", "accessToken", "create") { req async -> AccessTokenResponse in
AccessTokenResponse(accessToken: "fwPla7fQ8ty9+DZT/lD//uWZD4uD6C4lD6gGIIZTLKRTQ52/SLCRmk/370jcWGs+e+1iSoZtL7lj8ov9B0/jHmijH4nsHPQT6pchaQM1M9mtwYNQq0BWhVr9hF0jjCK/a5LIVd1kBac/Gemv29WKEDKSrUS9HxxUigoPRwtOy8m+oDj9FmDJZ+rzqWCc0QjES4Ky0fTpXZ7ESoguDzNmRtW3FYr+OFexw8wBPlwiC4w=", expiryTime: Int(Date.init(timeIntervalSinceNow: .init(0)).timeIntervalSince1970))
}
group.post("v3", "agreement", "getForLogin") { req async throws -> String in
let body = try req.content.decode(LoginAgreementRequest.self, as: .json)
return #"""
{
"adAgreementStatus": "n",
"agreement": {
"E001": "n",
"E002": "n",
"E006": "n",
"N002": "n",
"N003": "n",
"timestamp": "\#(Int(Date().timeIntervalSince1970) * 1000)"
},
"agreementPopup": "n",
"appId": "\#(body.appId)",
"appName": "World Flipper (NA)",
"context": "login",
"country": "\#(body.country)",
"firstAgreement": "n",
"idpCode": "\#(body.idpCode)",
"idpId": "6076008646",
"informationSecurityCountry": "kr",
"kakaoSyncAgreementGetSet": "n",
"kakaoSyncStatus": "off",
"kakaogameSdkVer": "3.0",
"lang": "\#(body.lang)",
"partnerId": 825,
"partnerName": " ",
"plusFriendStatusInfo": null,
"policyApplyTime": 1630854000000
}
"""#
}
group.post("v4", "auth", "loginDevice") { req async throws -> Response in
let body = try req.content.decode(LoginDeviceRequest.self, as: .json)
dump(body)
if let rawAccountId = req.headers["playerId"].first {
}
return Response(status: .notImplemented)
}
}
}
struct AccessTokenResponse: Content {
let accessToken: String
let expiryTime: Int
}
struct LoginAgreementRequest: Content {
let deviceId: String
let os: String
let country: String
let lang: String
let appId: String
let idpCode: String
let serialNo: String
let idpId: String
}
struct LoginDeviceRequest: Content {
let lang: String
let clientTime: Int
let deviceId: String
let serialNo: String
let country: String
let whiteKey: String
let market: String
let appSecret: String
let deviceAppKey: String
let sdkVer: String
let appVer: String
let os: String
let loginType: String
let accessToken: String
let resume: Bool
let osVer: String
let appId: String
let deviceModel: String
let network: String
let isIosAppOnMac: Bool
let adid: String
let timezoneOffset: Int
let fields: [String]
let telecom: String
}
struct LoginDeviceResponse: Content {
let zatExpiryTime: Int
let zrtExpiryTime: Int
let firstLogin: Bool
let externalToken: String
let zat: String
let zrt: String
let player: Player
}
struct Player: Content {
let idpId: String
let appId: String
let lang: String
let playerId: String
let agreement: AgreementResponse
let pushOption: PushOptionResponse
let lastLoginTime: Int
let regTime: Int
let idpAlias: String
let firstLoginTime: Int
let status: String
}
struct AgreementResponse: Content {
let E001: String
let E002: String
let E006: String
let N002: String
let N003: String
let timestamp: String
}
struct PushOptionResponse: Content {
let night: String
let player: String
}

View File

@@ -2,7 +2,7 @@ import Fluent
import Vapor
func routes(_ app: Application) throws {
app.get { req async in
app.get { req async in
"It works!"
}
@@ -10,5 +10,10 @@ app.get { req async in
"Hello, world!"
}
try app.register(collection: TodoController())
let openApi = OpenApi()
openApi.registerRoutes(app)
try app.register(collection: InfodeskController())
print(app.routes.all)
}

59
mitm-redirect-traffic.py Normal file
View File

@@ -0,0 +1,59 @@
from mitmproxy import http, dns
import ipaddress
import logging
API_HOST = "localhost"
# 198.51.100.0/24 subnet reserved for documentation, so it will never be used for anything else
#We can black-hole this address because it will be discarded.
API_DNS_REDIRECT_HOST = ipaddress.IPv4Address("198.51.100.140")
DNS_TTL= 600
API_PORT = 8000
API_SCHEME = 'http'
MAGIC_DOMAIN_SUFFIX = ".mitm.it"
prefixes = ["/openapi", "/infodesk", "", '/patch']
# hostname: prefix_index
hosts = {
# openapi
"openapi-zinny3.game.kakao.com": 0,
"gc-openapi-zinny3.kakaogames.com": 0,
# infodesk
"gc-infodesk-zinny3.kakaogames.com": 1,
# na server
"na.wdfp.kakaogames.com": 2,
# patch
"patch.wdfp.kakaogames.com": 3
}
def dns_request(flow: dns.DNSFlow):
if not flow.request.query or flow.request.questions is None: return
logging.info(f"[INFO] DNS request for {flow.request.questions}")
for question in flow.request.questions:
name = question.name
prefix_type = hosts.get(name) if question.type == 1 else None
if prefix_type != None: #Type is 1 when asking for an A record
#logging.info(f"[INFO] Matched DNS request for {question.name}")
flow.response.answers = [answer for answer in flow.response.answers if answer.name != question.name]
domain_redirect = f'{question.name}{MAGIC_DOMAIN_SUFFIX}'
#TODO: Are the CNAME records still useful in this configuration? Might be better to remove them and the host_redirects altogether....
cname_rec = dns.ResourceRecord.CNAME(question.name, domain_redirect, ttl=DNS_TTL)
a_rec = dns.ResourceRecord.A(domain_redirect, API_DNS_REDIRECT_HOST, ttl=DNS_TTL)
flow.response.answers.append(cname_rec)
flow.response.answers.append(a_rec)
logging.info(f"[INFO] Answered with {flow.response.answers}")
def request(flow: http.HTTPFlow):
logging.info(f"[INFO] {flow.request.url}")
prefix_type = hosts.get(flow.request.pretty_host)
if prefix_type != None:
flow.request.host = API_HOST
flow.request.port = API_PORT
flow.request.scheme = API_SCHEME
prefix = prefixes[prefix_type]
if prefix != "":
flow.request.path = f"{prefix}{flow.request.path}"