mirror of
https://github.com/MatthewL246/pretendo-docker.git
synced 2026-04-26 02:17:57 -05:00
Create Cemu online files generation script
The patch to restore downloading online files from the website will be removed, as Pretendo will never add this as an optional website feature.
This commit is contained in:
parent
019e15cfe1
commit
5e11ba3fe3
|
|
@ -26,21 +26,20 @@ This guide will show you how to access your server from the Cemu emulator.
|
|||
|
||||
<TabItem value="no-wiiu" label="Without a Wii U">
|
||||
<Admonition type="warning">
|
||||
Prefer using the Wii U method if you have access to a Wii U console. This method is more complicated and
|
||||
requires using an account server patch that disables the console verification, which normally blocks invalid OTP
|
||||
and SEEPROM dumps. **The fake OTP and SEEPROM dumps will not work on the official Pretendo server.**
|
||||
Prefer using the Wii U method if you have access to a Wii U console. This method is more complicated and requires
|
||||
using an account server patch that disables console verification, which normally blocks invalid OTP and SEEPROM
|
||||
dumps. **The fake OTP and SEEPROM dumps will not work on the official Pretendo server.**
|
||||
</Admonition>
|
||||
|
||||
1. Follow the [browser connecting guide](./browser.mdx) first.
|
||||
2. Visit [the account settings page](https://pretendo.network/account) in your proxied browser and click the
|
||||
`Download account files` button.
|
||||
<Admonition type="info">
|
||||
This button will only show up on your server. This feature was purposefully disabled on the official Pretendo
|
||||
servers to prevent abuse and ban evasion.
|
||||
</Admonition>
|
||||
3. Copy `otp.bin`, `seeprom.bin`, and `mlc01` from the downloaded ZIP file to your Cemu directory.
|
||||
4. Continue with the [official Pretendo Network Cemu installation guide](https://pretendo.network/docs/install/cemu)
|
||||
to enable online mode with Pretendo.
|
||||
1. Run `./scripts/create-cemu-online-files.sh --fake-dumps <pnid>` to generate the necessary online files, including
|
||||
the `account.dat` and the fake dumps. Replace `<pnid>` with your PNID username, and enter the password when
|
||||
prompted.
|
||||
- If you already have another account in Cemu, you can use the `--persistent-id` option to change the persistent
|
||||
ID (like `80000001`) of the generated `account.dat` to one that is not already in use.
|
||||
2. Copy `otp.bin`, `seeprom.bin`, and `mlc01` from the created `online-files` directory to your Cemu directory.
|
||||
Merge the `mlc01` directory with your existing Cemu MLC directory if you have one.
|
||||
3. Continue with the [official Pretendo Network Cemu installation guide](https://pretendo.network/docs/install/cemu)
|
||||
to enable online mode with Pretendo in the account settings.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
|
|
|||
65
scripts/create-cemu-online-files.sh
Executable file
65
scripts/create-cemu-online-files.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck source=./internal/framework.sh
|
||||
source "$(dirname "$(realpath "$0")")/internal/framework.sh"
|
||||
set_description "This creates the necessary files for Cemu online play with Pretendo as an alternative to using Dumpling.\
|
||||
It can also create fake OTP and SEEPROM dumps, which will only work on servers with console verification disabled."
|
||||
add_option "-f --force" "force" "Always overwrite the existing online files in the output directory without asking"
|
||||
add_option "-d --fake-dumps" "fake_dumps" "Create fake OTP and SEEPROM dumps (with all null bytes) in addition to the account.dat file"
|
||||
add_option_with_value "-i --persistent-id" "persistent_id" "id" "The persistent ID to use for the account.dat file" false "80000001"
|
||||
add_option_with_value "-o --output" "output_dir" "directory" "The output directory for the online files" false "./online-files"
|
||||
add_option_with_value "-p --password" "password" "password" "The password to use for the account.dat file (if not provided, you will be prompted to enter a password)" false
|
||||
add_positional_argument "pnid" "pnid" "The PNID to create an account.dat file" true
|
||||
parse_arguments "$@"
|
||||
|
||||
if [[ -z "$password" ]]; then
|
||||
printf "Enter the password for PNID $pnid: "
|
||||
read -rs password
|
||||
echo
|
||||
fi
|
||||
|
||||
account_dat_path="$output_dir/mlc01/usr/save/system/act/$persistent_id/account.dat"
|
||||
otp_path="$output_dir/otp.bin"
|
||||
seeprom_path="$output_dir/seeprom.bin"
|
||||
if [[ -n "$fake_dumps" ]]; then
|
||||
paths=("$account_dat_path" "$otp_path" "$seeprom_path")
|
||||
else
|
||||
paths=("$account_dat_path")
|
||||
fi
|
||||
|
||||
needs_confirmation=false
|
||||
for path in "${paths[@]}"; do
|
||||
mkdir -p "$(dirname "$path")"
|
||||
if [[ -f "$path" ]]; then
|
||||
print_warning "Output file $path already exists. Continuing will overwrite it!"
|
||||
needs_confirmation=true
|
||||
fi
|
||||
done
|
||||
if [[ "$needs_confirmation" == true && -z "$force" ]]; then
|
||||
printf "Continue? [y/N] "
|
||||
read -r continue
|
||||
if [[ "$continue" != "Y" && "$continue" != "y" ]]; then
|
||||
echo "Aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
print_info "Generating online files for PNID $pnid..."
|
||||
|
||||
compose_no_progress up -d account
|
||||
|
||||
create_account_dat_script=$(cat "$git_base_dir/scripts/run-in-container/create-account-dat.js")
|
||||
|
||||
docker compose exec -u root account sh -c "touch /tmp/account.dat && chmod 777 /tmp/account.dat"
|
||||
run_verbose docker compose exec account node -e "$create_account_dat_script" "$pnid" "$password" "$persistent_id"
|
||||
|
||||
compose_no_progress cp account:/tmp/account.dat "$account_dat_path"
|
||||
docker compose exec -u root account rm -f /tmp/account.dat
|
||||
|
||||
if [[ -n "$fake_dumps" ]]; then
|
||||
print_info "Creating fake OTP and SEEPROM dumps..."
|
||||
head -c 1024 /dev/zero >"$otp_path"
|
||||
head -c 512 /dev/zero >"$seeprom_path"
|
||||
fi
|
||||
|
||||
print_success "Successfully generated online files for PNID $pnid."
|
||||
70
scripts/run-in-container/create-account-dat.js
Normal file
70
scripts/run-in-container/create-account-dat.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// This should be evaled in the account container
|
||||
const fs = require("fs").promises;
|
||||
const { v4: uuidv4 } = require("uuid");
|
||||
const { compare } = require("bcrypt");
|
||||
const { config } = require("./dist/config-manager");
|
||||
const { connect } = require("./dist/database");
|
||||
const { PNID } = require("./dist/models/pnid");
|
||||
const { nintendoPasswordHash } = require("./dist/util");
|
||||
|
||||
// See https://github.com/GabIsAwesome/accountfile-generator and
|
||||
// https://github.com/PretendoNetwork/website/blob/99ee7ebe0aa1c2b632526f1de42f9f8b0d15940d/src/routes/account.js#L245-L284
|
||||
|
||||
async function runAsync() {
|
||||
if (process.argv.length < 4) {
|
||||
console.log("Usage: <pnid-username> <password> <persistent-id>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await connect();
|
||||
|
||||
const pnid = await PNID.findOne({
|
||||
usernameLower: process.argv[1].toLowerCase(),
|
||||
});
|
||||
if (pnid) {
|
||||
const accountDat = await generateAccountDat(pnid, process.argv[2], process.argv[3]);
|
||||
await fs.writeFile(`/tmp/account.dat`, accountDat);
|
||||
} else {
|
||||
throw new Error(`No PNID found for username ${process.argv[1]}.`);
|
||||
}
|
||||
}
|
||||
|
||||
runAsync().then(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
async function generateAccountDat(pnid, password, persistentId) {
|
||||
const hashedPassword = nintendoPasswordHash(password, pnid.pid);
|
||||
if (!(await compare(hashedPassword, pnid.password))) {
|
||||
throw new Error("Incorrect password specified.");
|
||||
}
|
||||
|
||||
const [year, month, day] = pnid.birthdate.split("-");
|
||||
const birthYear = parseInt(year, 10);
|
||||
const birthMonth = parseInt(month, 10);
|
||||
const birthDay = parseInt(day, 10);
|
||||
|
||||
let accountDat = "AccountInstance_00000000\n";
|
||||
accountDat += `PersistentId=${persistentId}\n`;
|
||||
accountDat += "TransferableIdBase=0\n";
|
||||
accountDat += `Uuid=${uuidv4().replace(/-/g, "")}\n`;
|
||||
accountDat += `MiiData=${Buffer.from(pnid.mii.data, "base64").toString("hex")}\n`;
|
||||
accountDat += `MiiName=${Buffer.from(pnid.mii.name, "utf16le").swap16().toString("hex")}\n`;
|
||||
accountDat += `AccountId=${pnid.username}\n`;
|
||||
accountDat += `BirthYear=${birthYear.toString(16)}\n`;
|
||||
accountDat += `BirthMonth=${birthMonth.toString(16)}\n`;
|
||||
accountDat += `BirthDay=${birthDay.toString(16)}\n`;
|
||||
accountDat += `Gender=${pnid.gender === "M" ? 1 : 0}\n`;
|
||||
accountDat += "IsMailAddressValidated=1\n";
|
||||
accountDat += `EmailAddress=${pnid.email.address}\n`;
|
||||
// No convenient way to turn the country code into the necessary numerical ID format
|
||||
accountDat += "Country=0\n";
|
||||
accountDat += "SimpleAddressId=0\n";
|
||||
accountDat += `PrincipalId=${pnid.pid.toString(16)}\n`;
|
||||
accountDat += "NeedsToDownloadMiiImage=1\n";
|
||||
accountDat += `MiiImageUrl=${config.cdn.base_url}/mii/${pnid.pid}/standard.tga\n`;
|
||||
accountDat += "IsPasswordCacheEnabled=1\n";
|
||||
accountDat += `AccountPasswordCache=${hashedPassword}`;
|
||||
|
||||
return accountDat;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user