From 0861c20100b09226d608c4899bf0506d16b41da3 Mon Sep 17 00:00:00 2001
From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com>
Date: Sun, 23 Jun 2024 18:28:32 -0400
Subject: [PATCH] Privatized many functions and classes that should be private
Also changed some imports to import as _name so that stuff like dataclass()
doesn't appear as available under libWiiPy.title
---
.gitignore | 1 +
src/libWiiPy/archive/ash.py | 4 ++--
src/libWiiPy/archive/u8.py | 26 ++++++++++++------------
src/libWiiPy/shared.py | 32 +++++-------------------------
src/libWiiPy/title/crypto.py | 38 ++++++++++++++++++++++++++++--------
src/libWiiPy/title/nus.py | 22 ++++++++++-----------
src/libWiiPy/title/ticket.py | 32 ++++++++++++++++++++++++++----
src/libWiiPy/title/wad.py | 26 ++++++++++++------------
src/libWiiPy/types.py | 21 --------------------
tests/test_commonkeys.py | 8 ++++----
10 files changed, 107 insertions(+), 103 deletions(-)
diff --git a/.gitignore b/.gitignore
index 8522187..d9ac8d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@ cython_debug/
*.tmd
*.wad
*.arc
+*.ash
out_prod/
remakewad.pl
diff --git a/src/libWiiPy/archive/ash.py b/src/libWiiPy/archive/ash.py
index 7be003d..4ff2a05 100644
--- a/src/libWiiPy/archive/ash.py
+++ b/src/libWiiPy/archive/ash.py
@@ -8,10 +8,10 @@
# See for details about the ASH archive format.
import io
-from dataclasses import dataclass
+from dataclasses import dataclass as _dataclass
-@dataclass
+@_dataclass
class _ASHBitReader:
"""
An _ASHBitReader class used to parse individual words in an ASH file. Private class used by the ASH module.
diff --git a/src/libWiiPy/archive/u8.py b/src/libWiiPy/archive/u8.py
index f7c4de8..b80cfa7 100644
--- a/src/libWiiPy/archive/u8.py
+++ b/src/libWiiPy/archive/u8.py
@@ -6,17 +6,17 @@
import io
import os
import pathlib
-from dataclasses import dataclass
+from dataclasses import dataclass as _dataclass
from typing import List
-from ..shared import align_value
+from ..shared import _align_value
-@dataclass
-class U8Node:
+@_dataclass
+class _U8Node:
"""
A U8Node object that contains the data of a single node in a U8 file header. Each node keeps track of whether this
node is for a file or directory, the offset of the name of the file/directory, the offset of the data for the file/
- directory, and the size of the data.
+ directory, and the size of the data. Private class used by functions and methods in the U8 module.
Attributes
----------
@@ -44,7 +44,7 @@ class U8Archive:
----------
"""
self.u8_magic = b''
- self.u8_node_list: List[U8Node] = [] # All the nodes in the header of a U8 file.
+ self.u8_node_list: List[_U8Node] = [] # All the nodes in the header of a U8 file.
self.file_name_list: List[str] = []
self.file_data_list: List[bytes] = []
self.u8_file_structure = dict
@@ -86,7 +86,7 @@ class U8Archive:
node_name_offset = int.from_bytes(u8_data.read(2))
node_data_offset = int.from_bytes(u8_data.read(4))
node_size = int.from_bytes(u8_data.read(4))
- self.u8_node_list.append(U8Node(node_type, node_name_offset, node_data_offset, node_size))
+ self.u8_node_list.append(_U8Node(node_type, node_name_offset, node_data_offset, node_size))
# Iterate over all loaded nodes and create a list of file names and a list of file data.
name_base_offset = u8_data.tell()
for node in self.u8_node_list:
@@ -121,7 +121,7 @@ class U8Archive:
for file_name in self.file_name_list:
header_size += len(file_name) + 1
# The initial data offset is equal to the file header (32 bytes) + node data aligned to 16 bytes.
- data_offset = align_value(header_size + 32, 16)
+ data_offset = _align_value(header_size + 32, 16)
# Adjust all nodes to place file data in the same order as the nodes. Why isn't it already like this?
current_data_offset = data_offset
for node in range(len(self.u8_node_list)):
@@ -241,7 +241,7 @@ def _pack_u8_dir(u8_archive: U8Archive, current_path, node_count, name_offset):
node_count += 1
u8_archive.file_name_list.append(file)
u8_archive.file_data_list.append(open(current_path.joinpath(file), "rb").read())
- u8_archive.u8_node_list.append(U8Node(0, name_offset, 0, len(u8_archive.file_data_list[-1])))
+ u8_archive.u8_node_list.append(_U8Node(0, name_offset, 0, len(u8_archive.file_data_list[-1])))
name_offset = name_offset + len(file) + 1 # Add 1 to accommodate the null byte at the end of the name.
# For directories, add their name to the file name list, add empty data to the file data list (since they obviously
# wouldn't have any), find the total number of files and directories inside the directory to calculate the final
@@ -251,7 +251,7 @@ def _pack_u8_dir(u8_archive: U8Archive, current_path, node_count, name_offset):
u8_archive.file_name_list.append(directory)
u8_archive.file_data_list.append(b'')
max_node = node_count + sum(1 for _ in current_path.joinpath(directory).rglob('*'))
- u8_archive.u8_node_list.append(U8Node(256, name_offset, 0, max_node))
+ u8_archive.u8_node_list.append(_U8Node(256, name_offset, 0, max_node))
name_offset = name_offset + len(directory) + 1 # Add 1 to accommodate the null byte at the end of the name.
u8_archive, node_count, name_offset = _pack_u8_dir(u8_archive, current_path.joinpath(directory), node_count,
name_offset)
@@ -280,7 +280,7 @@ def pack_u8(input_path) -> bytes:
u8_archive = U8Archive()
u8_archive.file_name_list.append("")
u8_archive.file_data_list.append(b'')
- u8_archive.u8_node_list.append(U8Node(256, 0, 0, sum(1 for _ in input_path.rglob('*')) + 1))
+ u8_archive.u8_node_list.append(_U8Node(256, 0, 0, sum(1 for _ in input_path.rglob('*')) + 1))
# Call the private function _pack_u8_dir() on the root note, which will recursively call itself to pack every
# subdirectory and file. Discard node_count and name_offset since we don't care about them here, as they're
# really only necessary for the directory recursion.
@@ -300,8 +300,8 @@ def pack_u8(input_path) -> bytes:
u8_archive.file_data_list.append(b'')
u8_archive.file_data_list.append(file_data)
# Append generic U8Node for the root, followed by the actual file's node.
- u8_archive.u8_node_list.append(U8Node(256, 0, 0, 2))
- u8_archive.u8_node_list.append(U8Node(0, 1, 0, len(file_data)))
+ u8_archive.u8_node_list.append(_U8Node(256, 0, 0, 2))
+ u8_archive.u8_node_list.append(_U8Node(0, 1, 0, len(file_data)))
return u8_archive.dump()
else:
raise FileNotFoundError("Input file/directory: \"" + str(input_path) + "\" does not exist!")
diff --git a/src/libWiiPy/shared.py b/src/libWiiPy/shared.py
index 7157dc6..3b697d8 100644
--- a/src/libWiiPy/shared.py
+++ b/src/libWiiPy/shared.py
@@ -4,12 +4,10 @@
# This file defines general functions that may be useful in other modules of libWiiPy. Putting them here cuts down on
# clutter in other files.
-import binascii
-
-def align_value(value, alignment=64) -> int:
+def _align_value(value, alignment=64) -> int:
"""
- Aligns the provided value to the set alignment (defaults to 64).
+ Aligns the provided value to the set alignment (defaults to 64). Private function used by other libWiiPy modules.
Parameters
----------
@@ -29,9 +27,10 @@ def align_value(value, alignment=64) -> int:
return value
-def pad_bytes(data, alignment=64) -> bytes:
+def _pad_bytes(data, alignment=64) -> bytes:
"""
- Pads the provided bytes object to the provided alignment (defaults to 64).
+ Pads the provided bytes object to the provided alignment (defaults to 64). Private function used by other libWiiPy
+ modules.
Parameters
----------
@@ -48,24 +47,3 @@ def pad_bytes(data, alignment=64) -> bytes:
while (len(data) % alignment) != 0:
data += b'\x00'
return data
-
-
-def convert_tid_to_iv(title_id: str) -> bytes:
- title_key_iv = b''
- if type(title_id) is bytes:
- # This catches the format b'0000000100000002'
- if len(title_id) == 16:
- title_key_iv = binascii.unhexlify(title_id)
- # This catches the format b'\x00\x00\x00\x01\x00\x00\x00\x02'
- elif len(title_id) == 8:
- pass
- # If it isn't one of those lengths, it cannot possibly be valid, so reject it.
- else:
- raise ValueError("Title ID is not valid!")
- # Allow for a string like "0000000100000002"
- elif type(title_id) is str:
- title_key_iv = binascii.unhexlify(title_id)
- # If the Title ID isn't bytes or a string, it isn't valid and is rejected.
- else:
- raise TypeError("Title ID type is not valid! It must be either type str or bytes.")
- return title_key_iv
diff --git a/src/libWiiPy/title/crypto.py b/src/libWiiPy/title/crypto.py
index d7e6f72..56a02f6 100644
--- a/src/libWiiPy/title/crypto.py
+++ b/src/libWiiPy/title/crypto.py
@@ -2,10 +2,32 @@
# https://github.com/NinjaCheetah/libWiiPy
import struct
+import binascii
from .commonkeys import get_common_key
-from ..shared import convert_tid_to_iv
+from Crypto.Cipher import AES as _AES
-from Crypto.Cipher import AES
+
+def _convert_tid_to_iv(title_id: str) -> bytes:
+ # Converts a Title ID in various formats into the format required to act as an IV. Private function used by other
+ # crypto functions.
+ title_key_iv = b''
+ if type(title_id) is bytes:
+ # This catches the format b'0000000100000002'
+ if len(title_id) == 16:
+ title_key_iv = binascii.unhexlify(title_id)
+ # This catches the format b'\x00\x00\x00\x01\x00\x00\x00\x02'
+ elif len(title_id) == 8:
+ pass
+ # If it isn't one of those lengths, it cannot possibly be valid, so reject it.
+ else:
+ raise ValueError("Title ID is not valid!")
+ # Allow for a string like "0000000100000002"
+ elif type(title_id) is str:
+ title_key_iv = binascii.unhexlify(title_id)
+ # If the Title ID isn't bytes or a string, it isn't valid and is rejected.
+ else:
+ raise TypeError("Title ID type is not valid! It must be either type str or bytes.")
+ return title_key_iv
def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: bytes | str) -> bytes:
@@ -31,11 +53,11 @@ def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: byt
# Load the correct common key for the title.
common_key = get_common_key(common_key_index)
# Convert the IV into the correct format based on the type provided.
- title_key_iv = convert_tid_to_iv(title_id)
+ title_key_iv = _convert_tid_to_iv(title_id)
# The IV will always be in the same format by this point, so add the last 8 bytes.
title_key_iv = title_key_iv + (b'\x00' * 8)
# Create a new AES object with the values provided.
- aes = AES.new(common_key, AES.MODE_CBC, title_key_iv)
+ aes = _AES.new(common_key, _AES.MODE_CBC, title_key_iv)
# Decrypt the Title Key using the AES object.
title_key = aes.decrypt(title_key_enc)
return title_key
@@ -64,11 +86,11 @@ def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: byt
# Load the correct common key for the title.
common_key = get_common_key(common_key_index)
# Convert the IV into the correct format based on the type provided.
- title_key_iv = convert_tid_to_iv(title_id)
+ title_key_iv = _convert_tid_to_iv(title_id)
# The IV will always be in the same format by this point, so add the last 8 bytes.
title_key_iv = title_key_iv + (b'\x00' * 8)
# Create a new AES object with the values provided.
- aes = AES.new(common_key, AES.MODE_CBC, title_key_iv)
+ aes = _AES.new(common_key, _AES.MODE_CBC, title_key_iv)
# Encrypt Title Key using the AES object.
title_key = aes.encrypt(title_key_dec)
return title_key
@@ -105,7 +127,7 @@ def decrypt_content(content_enc, title_key, content_index, content_length) -> by
if (len(content_enc) % 16) != 0:
content_enc = content_enc + (b'\x00' * (16 - (len(content_enc) % 16)))
# Create a new AES object with the values provided, with the content's unique ID as the IV.
- aes = AES.new(title_key, AES.MODE_CBC, content_index_bin)
+ aes = _AES.new(title_key, _AES.MODE_CBC, content_index_bin)
# Decrypt the content using the AES object.
content_dec = aes.decrypt(content_enc)
# Trim additional bytes that may have been added so the content is the correct size.
@@ -144,7 +166,7 @@ def encrypt_content(content_dec, title_key, content_index) -> bytes:
if (len(content_dec) % 16) != 0:
content_dec = content_dec + (b'\x00' * (16 - (len(content_dec) % 16)))
# Create a new AES object with the values provided, with the content's unique ID as the IV.
- aes = AES.new(title_key, AES.MODE_CBC, content_index_bin)
+ aes = _AES.new(title_key, _AES.MODE_CBC, content_index_bin)
# Encrypt the content using the AES object.
content_enc = aes.encrypt(content_dec)
# Trim down the encrypted content.
diff --git a/src/libWiiPy/title/nus.py b/src/libWiiPy/title/nus.py
index 093627c..cbf0fa6 100644
--- a/src/libWiiPy/title/nus.py
+++ b/src/libWiiPy/title/nus.py
@@ -10,7 +10,7 @@ from .title import Title
from .tmd import TMD
from .ticket import Ticket
-nus_endpoint = ["http://nus.cdn.shop.wii.com/ccs/download/", "http://ccs.cdn.wup.shop.nintendo.net/ccs/download/"]
+_nus_endpoint = ["http://nus.cdn.shop.wii.com/ccs/download/", "http://ccs.cdn.wup.shop.nintendo.net/ccs/download/"]
def download_title(title_id: str, title_version: int = None, wiiu_endpoint: bool = False) -> Title:
@@ -68,9 +68,9 @@ def download_tmd(title_id: str, title_version: int = None, wiiu_endpoint: bool =
# Build the download URL. The structure is download//tmd for latest and download//tmd. for
# when a specific version is requested.
if wiiu_endpoint is False:
- tmd_url = nus_endpoint[0] + title_id + "/tmd"
+ tmd_url = _nus_endpoint[0] + title_id + "/tmd"
else:
- tmd_url = nus_endpoint[1] + title_id + "/tmd"
+ tmd_url = _nus_endpoint[1] + title_id + "/tmd"
# Add the version to the URL if one was specified.
if title_version is not None:
tmd_url += "." + str(title_version)
@@ -109,9 +109,9 @@ def download_ticket(title_id: str, wiiu_endpoint: bool = False) -> bytes:
# Build the download URL. The structure is download//cetk, and cetk will only exist if this is a free
# title.
if wiiu_endpoint is False:
- ticket_url = nus_endpoint[0] + title_id + "/cetk"
+ ticket_url = _nus_endpoint[0] + title_id + "/cetk"
else:
- ticket_url = nus_endpoint[1] + title_id + "/cetk"
+ ticket_url = _nus_endpoint[1] + title_id + "/cetk"
# Make the request.
ticket_request = requests.get(url=ticket_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True)
if ticket_request.status_code != 200:
@@ -142,11 +142,11 @@ def download_cert(wiiu_endpoint: bool = False) -> bytes:
"""
# Download the TMD and cetk for the System Menu 4.3U.
if wiiu_endpoint is False:
- tmd_url = nus_endpoint[0] + "0000000100000002/tmd.513"
- cetk_url = nus_endpoint[0] + "0000000100000002/cetk"
+ tmd_url = _nus_endpoint[0] + "0000000100000002/tmd.513"
+ cetk_url = _nus_endpoint[0] + "0000000100000002/cetk"
else:
- tmd_url = nus_endpoint[1] + "0000000100000002/tmd.513"
- cetk_url = nus_endpoint[1] + "0000000100000002/cetk"
+ tmd_url = _nus_endpoint[1] + "0000000100000002/tmd.513"
+ cetk_url = _nus_endpoint[1] + "0000000100000002/cetk"
tmd = requests.get(url=tmd_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content
cetk = requests.get(url=cetk_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content
# Assemble the certificate.
@@ -186,9 +186,9 @@ def download_content(title_id: str, content_id: int, wiiu_endpoint: bool = False
if len(content_id_hex) < 2:
content_id_hex = "0" + content_id_hex
if wiiu_endpoint is False:
- content_url = nus_endpoint[0] + title_id + "/000000" + content_id_hex
+ content_url = _nus_endpoint[0] + title_id + "/000000" + content_id_hex
else:
- content_url = nus_endpoint[1] + title_id + "/000000" + content_id_hex
+ content_url = _nus_endpoint[1] + title_id + "/000000" + content_id_hex
# Make the request.
content_request = requests.get(url=content_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True)
if content_request.status_code != 200:
diff --git a/src/libWiiPy/title/ticket.py b/src/libWiiPy/title/ticket.py
index 405b290..8b6b5ca 100644
--- a/src/libWiiPy/title/ticket.py
+++ b/src/libWiiPy/title/ticket.py
@@ -5,11 +5,33 @@
import io
import binascii
+from dataclasses import dataclass as _dataclass
from .crypto import decrypt_title_key
-from ..types import TitleLimit
from typing import List
+@_dataclass
+class _TitleLimit:
+ """
+ A TitleLimit object that contains the type of restriction and the limit. The limit type can be one of the following:
+ 0 = None, 1 = Time Limit, 3 = None, or 4 = Launch Count. The maximum usage is then either the time in minutes the
+ title can be played or the maximum number of launches allowed for that title, based on the type of limit applied.
+ Private class used only by the Ticket class.
+
+ Attributes
+ ----------
+ limit_type : int
+ The type of play limit applied.
+ maximum_usage : int
+ The maximum value for the type of play limit applied.
+ """
+ # The type of play limit applied.
+ # 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
+ limit_type: int
+ # The maximum value of the limit applied.
+ maximum_usage: int
+
+
class Ticket:
"""
A Ticket object that allows for either loading and editing an existing Ticket or creating one manually if desired.
@@ -47,12 +69,14 @@ class Ticket:
self.unknown1: bytes = b'' # Some unknown data, not always the same so reading it just in case.
self.title_version: int = 0 # Version of the ticket's associated title.
self.permitted_titles: bytes = b'' # Permitted titles mask
- self.permit_mask: bytes = b'' # "Permit mask. The current disc title is ANDed with the inverse of this mask to see if the result matches the Permitted Titles Mask."
+ # "Permit mask. The current disc title is ANDed with the inverse of this mask to see if the result matches the
+ # Permitted Titles Mask."
+ self.permit_mask: bytes = b''
self.title_export_allowed: int = 0 # Whether title export is allowed with a PRNG key or not.
self.common_key_index: int = 0 # Which common key should be used. 0 = Common Key, 1 = Korean Key, 2 = vWii Key
self.unknown2: bytes = b'' # More unknown data. Varies for VC/non-VC titles so reading it to ensure it matches.
self.content_access_permissions: bytes = b'' # "Content access permissions (one bit for each content)"
- self.title_limits_list: List[TitleLimit] = [] # List of play limits applied to the title.
+ self.title_limits_list: List[_TitleLimit] = [] # List of play limits applied to the title.
# v1 ticket data
# TODO: Write in v1 ticket attributes here. This code can currently only handle v0 tickets, and will reject v1.
@@ -134,7 +158,7 @@ class Ticket:
for limit in range(0, 8):
limit_type = int.from_bytes(ticket_data.read(4))
limit_value = int.from_bytes(ticket_data.read(4))
- self.title_limits_list.append(TitleLimit(limit_type, limit_value))
+ self.title_limits_list.append(_TitleLimit(limit_type, limit_value))
def dump(self) -> bytes:
"""
diff --git a/src/libWiiPy/title/wad.py b/src/libWiiPy/title/wad.py
index a06412b..afb5b5b 100644
--- a/src/libWiiPy/title/wad.py
+++ b/src/libWiiPy/title/wad.py
@@ -5,7 +5,7 @@
import io
import binascii
-from ..shared import align_value, pad_bytes
+from ..shared import _align_value, _pad_bytes
class WAD:
@@ -102,12 +102,12 @@ class WAD:
# ====================================================================================
wad_cert_offset = self.wad_hdr_size
# crl isn't ever used, however an entry for its size exists in the header, so its calculated just in case.
- wad_crl_offset = align_value(wad_cert_offset + self.wad_cert_size)
- wad_tik_offset = align_value(wad_crl_offset + self.wad_crl_size)
- wad_tmd_offset = align_value(wad_tik_offset + self.wad_tik_size)
+ wad_crl_offset = _align_value(wad_cert_offset + self.wad_cert_size)
+ wad_tik_offset = _align_value(wad_crl_offset + self.wad_crl_size)
+ wad_tmd_offset = _align_value(wad_tik_offset + self.wad_tik_size)
# meta isn't guaranteed to be used, but some older SDK titles use it, and not reading it breaks things.
- wad_meta_offset = align_value(wad_tmd_offset + self.wad_tmd_size)
- wad_content_offset = align_value(wad_meta_offset + self.wad_meta_size)
+ wad_meta_offset = _align_value(wad_tmd_offset + self.wad_tmd_size)
+ wad_content_offset = _align_value(wad_meta_offset + self.wad_meta_size)
# ====================================================================================
# Load data for each WAD section based on the previously calculated offsets.
# ====================================================================================
@@ -159,25 +159,25 @@ class WAD:
wad_data += int.to_bytes(self.wad_content_size, 4)
# WAD meta size.
wad_data += int.to_bytes(self.wad_meta_size, 4)
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the cert data and write it out.
wad_data += self.get_cert_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the crl data and write it out.
wad_data += self.get_crl_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the ticket data and write it out.
wad_data += self.get_ticket_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the TMD data and write it out.
wad_data += self.get_tmd_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the meta/footer data and write it out.
wad_data += self.get_meta_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
# Retrieve the content data and write it out.
wad_data += self.get_content_data()
- wad_data = pad_bytes(wad_data)
+ wad_data = _pad_bytes(wad_data)
return wad_data
def get_wad_type(self) -> str:
diff --git a/src/libWiiPy/types.py b/src/libWiiPy/types.py
index 155090e..f898d77 100644
--- a/src/libWiiPy/types.py
+++ b/src/libWiiPy/types.py
@@ -28,24 +28,3 @@ class ContentRecord:
content_type: int # Type of content, possible values of: 0x0001: Normal, 0x4001: DLC, 0x8001: Shared.
content_size: int
content_hash: bytes
-
-
-@dataclass
-class TitleLimit:
- """
- A TitleLimit object that contains the type of restriction and the limit. The limit type can be one of the following:
- 0 = None, 1 = Time Limit, 3 = None, or 4 = Launch Count. The maximum usage is then either the time in minutes the
- title can be played or the maximum number of launches allowed for that title, based on the type of limit applied.
-
- Attributes
- ----------
- limit_type : int
- The type of play limit applied.
- maximum_usage : int
- The maximum value for the type of play limit applied.
- """
- # The type of play limit applied.
- # 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
- limit_type: int
- # The maximum value of the limit applied.
- maximum_usage: int
diff --git a/tests/test_commonkeys.py b/tests/test_commonkeys.py
index 0bba6d5..a96b978 100644
--- a/tests/test_commonkeys.py
+++ b/tests/test_commonkeys.py
@@ -3,18 +3,18 @@
import unittest
-from libWiiPy import commonkeys
+from libWiiPy import title
class TestCommonKeys(unittest.TestCase):
def test_common(self):
- self.assertEqual(commonkeys.get_common_key(0), b'\xeb\xe4*"^\x85\x93\xe4H\xd9\xc5Es\x81\xaa\xf7')
+ self.assertEqual(title.get_common_key(0), b'\xeb\xe4*"^\x85\x93\xe4H\xd9\xc5Es\x81\xaa\xf7')
def test_korean(self):
- self.assertEqual(commonkeys.get_common_key(1), b'c\xb8+\xb4\xf4aN.\x13\xf2\xfe\xfb\xbaL\x9b~')
+ self.assertEqual(title.get_common_key(1), b'c\xb8+\xb4\xf4aN.\x13\xf2\xfe\xfb\xbaL\x9b~')
def test_vwii(self):
- self.assertEqual(commonkeys.get_common_key(2), b'0\xbf\xc7n|\x19\xaf\xbb#\x1630\xce\xd7\xc2\x8d')
+ self.assertEqual(title.get_common_key(2), b'0\xbf\xc7n|\x19\xaf\xbb#\x1630\xce\xd7\xc2\x8d')
if __name__ == '__main__':