This program DOES NOT encourage piracy at all!
It was designed to reduce the time to download/install a game from the Nintendo eShop.
In case you have a ADSL connection, to install latest Zelda
(14.4Gb) it can take ages!
On top of that, if you have bought a game on eShop like Jump Force, once it is not anymore on the shop how can you install it again?
Using your personal NSP dump, with tinfoil
and tinshop
everything should be fine and fast!
To proper use this software, here is the checklist:
- Optional: A proper configured
config.yaml
- Copy/Paste
config.example.yaml
toconfig.yaml
- Comment/Uncomment parts in the config according to your needs
- Copy/Paste
- Games should have in their name
[ID][v0]
to be recognized - Games extension should be
nsp
ornsz
- Retrieve binary from latest release or container or build from source (See
Dev
section below)
Now simply run it and add a shop inside tinfoil with the address setup in config
(or http://localIp:3000
if not specified).
Here is the list of all main features so far:
- Automatically download
titles.US.en.json
if missing at startup - Basic protection from forged queries (should allow only tinfoil to use the shop)
- Serve from several mounted directories
- Serve from several network directories (Using NFS)
- Display a webpage for forbidden devices
- Auto-refresh configuration on file change
- Add the possibility to whitelist or blacklist a switch
- Add the possibility to ban theme
- You can specify custom titledb to be merged with official one
- Auto-watch for mounted directories
- Add filters path for shop
- Simple ticket check in NSP/NSZ (based on titledb file)
- Collect basic statistics
- An API to query information about your shop
- Handle Basic Auth from Tinfoil through Forward Auth Endpoint
When you setup your shop inside tinfoil
you can now add the following path:
multi
: Filter only multiplayer gamesfr
,en
, ... : Filter by languagesworld
: All games without any filter (equivalent without path)
I suggest to use a tiny executable gow to help you during the process (hot reload, etc..).
For example I use the following command to develop gow -c run .
.
If you want to build TinShop
from source, please run go build
.
And then, simply run ./tinshop
.
To run with Docker, you can use this as a starting cli
example:
docker run -d --restart=always -e TINSHOP_SOURCES_DIRECTORIES=/games -e TINSHOP_WELCOMEMESSAGE="Welcome to my Tinshop!" -v /local/game/backups:/games -p 3000:3000
This will run Tinshop on http://localhost:3000
and persist across reboots!
If docker compose
is your thing, then start with this example:
version: '3.9'
services:
tinshop:
container_name: tinshop
image: helvio/tinshop:latest
restart: always
ports:
- 3000:3000
environment:
- TINSHOP_SOURCES_DIRECTORIES=/games
- TINSHOP_WELCOMEMESSAGE=Welcome to my Tinshop!
volumes:
- /media/switch:/games
All of the settings in the config.yaml
file are valid Environment Variables. They must be UPPERCASE
and prefixed by TINSHOP_
. Nested properties should be prefixed by _
. Here are a few examples:
ENV_VAR | config.yaml entry |
Default Value | Example Value |
---|---|---|---|
TINSHOP_HOST | host | <empty> |
tinshop.example.com |
TINSHOP_PROTOCOL | protocol | http |
https |
TINSHOP_NAME | name | TinShop |
MyShop |
TINSHOP_REVERSEPROXY | reverseProxy | false |
true |
TINSHOP_WELCOMEMESSAGE | welcomeMessage | Welcome to your own TinShop! |
Welcome to my shop! |
TINSHOP_NOWELCOMEMESSAGE | noWelcomeMessage | false |
true |
TINSHOP_DEBUG_NFS | debug.nfs | false |
true |
TINSHOP_DEBUG_NOSECURITY | debug.nosecurity | false |
true |
TINSHOP_DEBUG_TICKET | debug.ticket | false |
true |
TINSHOP_NSP_CHECKVERIFIED | nsp.checkVerified | false |
true |
TINSHOP_SOURCES_DIRECTORIES | sources.directories | ./games |
/games /path/two /path/three |
TINSHOP_SOURCES_NSF | sources.nfs | null |
192.168.1.100:/path/to/games |
TINSHOP_SECURITY_BANNEDTHEME | sources.bannedTheme | null |
THEME1 THEME2 THEME3 |
TINSHOP_SECURITY_WHITELIST | sources.whitelist | null |
NSWID1 NSWID2 NSWID3 |
TINSHOP_SECURITY_BLACKLIST | sources.blacklist | null |
NSWID4 NSWID5 NSWID6 |
TINSHOP_SECURITY_FORWARDAUTH | sources.forwardAuth | null |
https://auth.tinshop.com/switch |
Wanting to generate all possible os binaries (macOS, linux, windows) with all architectures (arm, amd64)?
Here is the command goreleaser release --snapshot --skip-publish --rm-dist
.
Dead simple, thanks to Golang!
If you change an interface (or add a new one), do not forget to execute ./update_mocks.sh
to generate up-to-date mocks for tests.
Do not forget to install mockgen
first:
go install github.com/golang/mock/mockgen@v1.6.0
You can run ginkgo -r
for one shot or ginkgo watch -r
during development.
Note: you can add -cover
to have an idea of the code coverage.
You can see the roadmap here.
If you have any suggestions, do not hesitate to participate!
Answer
It's dead simple, and no dependencies! It's just a single small executable.
Easier to install games without connecting switch or by updating SD card (Nightmare if you are on macOS).
The upcoming features will also be a huge advantage against others software.
Answer
By default, TinShop
will look into the games
directory relative to tinshop
executable.
However in the config.yaml
file, you can change this.
In the sources
section, you can have the following:
directories
: List of directories where you put your gamesnfs
: List of NFS shares that contains your games
Answer
Yes, you can!
Use a reverse proxy (like traefik, caddy, nginx...) to do tls termination and forward to your instance on port 3000
.
To work with caddy
, you need to put in your Caddyfile
something similar to this:
tinshop.example.com:80 {
reverse_proxy 192.168.1.2:3000
}
and your config.yaml
as follow:
host: tinshop.example.com
protocol: http
port: 3000
reverseProxy: true
If you want to have HTTPS, ensure caddy
handle it (it will with Let's Encrypt) and change https
in the config and remove :80
in the Caddyfile
example.
To work with traefik
, you need to put in your Dynamic Configuration something similar to this:
http:
routers:
service: tinshop
rule: Host(`tinshop.example.com`)
entryPoints: websecure # Could be web if not using https
services:
tinshop:
loadBalancer:
servers:
- url: http://192.168.1.2:3000
and your config.yaml
as follow:
host: tinshop.example.com
protocol: http
port: 3000
reverseProxy: true
If you want to have HTTPS, ensure traefik
can handle it (it will with Let's Encrypt) and use protocol https
in the config.
For more details on Traefik + Let's Encrypt, click here.
Answer
TinShop does handle basic auth but not by itself.
You should look for forwardAuth
in the config.yaml
to set the endpoint that will handle the authentication in behalf of TinShop.
In the future, a proper user management will be incorporated into TinShop to handle it.
In addition, for other type of protection, you can whitelist/blacklist your own switch and this will do the trick.
Answer
First, download and replace the latest titles.US.en.json
available (or delete it, it will be automatically downloaded at startup).
If this does not solve your issue, then you should use custom titledb entry to describe those which are missing.
Answer
The current implementation to verify the NSP/NSZ are basic and based on the Ticket information.
So you might still get some error about signature failed even with checkVerified
enabled.
Maybe later, this feature will be enhanced to add additional checks on game files (PR Welcome!).
Answer
You must follow the naming convention for the games as follow:
[gameId][version].(nsp/nsz)
gameId
should be a 16 characters long string.
For example, those are invalid:
0000000000000000 [v0].nsp
[0000000000000000].nsp
[0000000000000000][v0].xxx
Those are valid:
[0000000000000000] [v0].nsp
[0000000000000000][v131072].nsz
My Saved Game [0000000000000000] [v0].nsp
Awesome title [0000000000000000][v0] (15Gb).nsz
I would like to give back thanks to the people who helped me with or without knowing!
- Bogdan Rosu Creative for his shop icon.
- Dono for his support and tests.
- AdamK2003 for his up-to-date
titles.US.en.json
and his answers on discord. - nxdumptool for the information taken of NSP format
Rémy Boulanouar |
Helvio Pedreschi |
bay0 |