Mods encryption

master
Irrlick 2017-09-05 16:44:36 +02:00 committed by Pierre-Yves Rollo
parent d5a721dbc5
commit c92e3d5ed6
31 changed files with 1777 additions and 22 deletions

133
CHANGES.txt Normal file
View File

@ -0,0 +1,133 @@
1. Encryption
The Lua files can be encrypted using the 256 bit variant of the AES encryption algorithm.
The AES key is file name dependent, and is built using eight keys and eight prime numbers
defined in "adel/src/encryption_data.h".
#define ENCRYPTION_KEY_0 0x01234567
#define ENCRYPTION_KEY_1 0x01234567
#define ENCRYPTION_KEY_2 0x01234567
#define ENCRYPTION_KEY_3 0x01234567
#define ENCRYPTION_KEY_4 0x01234567
#define ENCRYPTION_KEY_5 0x01234567
#define ENCRYPTION_KEY_6 0x01234567
#define ENCRYPTION_KEY_7 0x01234567
#define ENCRYPTION_PRIME_0 0x01234567
#define ENCRYPTION_PRIME_1 0x01234567
#define ENCRYPTION_PRIME_2 0x01234567
#define ENCRYPTION_PRIME_3 0x01234567
#define ENCRYPTION_PRIME_4 0x01234567
#define ENCRYPTION_PRIME_5 0x01234567
#define ENCRYPTION_PRIME_6 0x01234567
#define ENCRYPTION_PRIME_7 0x01234567
Of course, the above values must be changed, if needed on a customer basis, and the version
of "encryption_data.h" which contains the actual keys and prime numbers used for encryption
must absolutely be kept secret, and thus should NEVER be put on a Github repository.
Be aware that when any key or prime number is changed in "encryption_data.h" :
- the encryption tool, the game client and the game server must be rebuilt so that they all
use the same keys.
- the decrypted Lua files must be encrypted with the new encryption tool.
- the server, the game and the encrypted Lua files must be deployed again.
Big 32-bit prime numbers can be generated here :
https://asecuritysite.com/encryption/random3?val=32
There is also a list with all the 32-bit prime numbers here :
http://www.fukudat.com/prime/prime.dat.gz
Sample data :
#define ENCRYPTION_KEY_0 0x9534A53F
#define ENCRYPTION_KEY_1 0xE53823C4
#define ENCRYPTION_KEY_2 0x31986584
#define ENCRYPTION_KEY_3 0x3919F129
#define ENCRYPTION_KEY_4 0x81683587
#define ENCRYPTION_KEY_5 0x16E81A34
#define ENCRYPTION_KEY_6 0xC9835185
#define ENCRYPTION_KEY_7 0x246D32F5
#define ENCRYPTION_PRIME_0 1977777259u
#define ENCRYPTION_PRIME_1 3392428841u
#define ENCRYPTION_PRIME_2 293353289u
#define ENCRYPTION_PRIME_3 891334331u
#define ENCRYPTION_PRIME_4 1926494413u
#define ENCRYPTION_PRIME_5 1460369081u
#define ENCRYPTION_PRIME_6 3938039173u
#define ENCRYPTION_PRIME_7 1340222629u
2. Encryption tool
Lua files can be encrypted/decrypted using a dedicated tool in the "adel/util/crypt/" folder.
The "-e" option is used to encrypt the files, and the "-d" option to decrypt them.
Only files which aren't already encrypted/decrypted are processed.
Files can be encrypted/decrypted manually, by providing their paths as additional arguments :
crypt -e *.lua
crypt -d *.lua
The recommended way to use the tool is to create a "CryptList.txt" file in the current folder
and call the tool without arguments :
crypt -e
crypt -d
This file should contain the paths of all the Lua files to encrypt or decrypt.
The "CryptList.txt" file can be generated automatically using the following Linux command :
find . -name "*.lua" > CryptList.txt
This command will create a "CryptList.txt" file with the paths of the Lua files of this folder
and its subfolder.
3. Compilation
Encryption tool :
cd adel/util/crypt/
rm CMakeCache.txt
cmake .
make
Game and server :
cd adel/
rm CMakeCache.txt
cmake . -DBUILD_CLIENT=1 -DBUILD_SERVER=1 -DRUN_IN_PLACE=TRUE
make
or
cd adel/
rm CMakeCache.txt
cmake . -DBUILD_CLIENT=1 -DBUILD_SERVER=1 -DRUN_IN_PLACE=TRUE -DENABLE_CURL=1 -DENABLE_CURSES=1 -DENABLE_LUAJIT=1
make
4. Usage
At any time, the Lua files can be decrypted and encrypted in place in the development folder.
A safer approach is to copy the Lua files to deploy in a temporary folder and encrypt them there
before deployment.
5. Signature tool
The "md5.sh" shell script in the "adel/util/md5/" allows to update the production database,
by generating an SQL script file with the required commands.
It will scan all Lua files in the current folder and generate SQL commands like this one :
update maps
set mods_hash_md5 = "c50f510b0072cb9467e0d4c43f96fcae"
where url_download = "http://assets.kidscode.com/master/test/x.lua";

View File

@ -549,6 +549,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
#if 0 // :PATCH:
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
LoadF lf;
int status, readstatus;
@ -588,6 +589,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
lua_remove(L, fnameindex);
return status;
}
#endif
typedef struct LoadS {

340
src/aes.h Normal file
View File

@ -0,0 +1,340 @@
/*
* Byte-oriented AES-256 implementation.
* All lookup tables replaced with 'on the fly' calculations.
*
* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
* Other contributors: Hal Finney
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0))
static unsigned char rj_xtime(unsigned char);
static void aes_subBytes(unsigned char *);
static void aes_subBytes_inv(unsigned char *);
static void aes_addRoundKey(unsigned char *, unsigned char *);
static void aes_addRoundKey_cpy(unsigned char *, unsigned char *, unsigned char *);
static void aes_shiftRows(unsigned char *);
static void aes_shiftRows_inv(unsigned char *);
static void aes_mixColumns(unsigned char *);
static void aes_mixColumns_inv(unsigned char *);
static void aes_expandEncKey(unsigned char *, unsigned char *);
static void aes_expandDecKey(unsigned char *, unsigned char *);
typedef struct {
unsigned char key[32];
unsigned char enckey[32];
unsigned char deckey[32];
} aes256_context;
static void aes256_init(aes256_context *, unsigned char * key);
static void aes256_done(aes256_context *);
static void aes256_encrypt_ecb(aes256_context *, unsigned char *plaintext);
static void aes256_decrypt_ecb(aes256_context *, unsigned char *cipertext);
static const unsigned char sbox[256] =
{
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
static const unsigned char sboxinv[256] =
{
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
#define rj_sbox(x) sbox[(x)]
#define rj_sbox_inv(x) sboxinv[(x)]
static unsigned char rj_xtime(unsigned char x)
{
unsigned char y = (unsigned char)(x << 1);
return (x & 0x80) ? (y ^ 0x1b) : y;
}
static void aes_subBytes(unsigned char *buf)
{
register unsigned char i = 16;
while (i--) buf[i] = rj_sbox(buf[i]);
}
static void aes_subBytes_inv(unsigned char *buf)
{
register unsigned char i = 16;
while (i--) buf[i] = rj_sbox_inv(buf[i]);
}
static void aes_addRoundKey(unsigned char *buf, unsigned char *key)
{
register unsigned char i = 16;
while (i--) buf[i] ^= key[i];
}
static void aes_addRoundKey_cpy(unsigned char *buf, unsigned char *key, unsigned char *cpk)
{
register unsigned char i = 16;
while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16 + i] = key[16 + i];
}
static void aes_shiftRows(unsigned char *buf)
{
register unsigned char i, j;
i = buf[1], buf[1] = buf[5], buf[5] = buf[9], buf[9] = buf[13], buf[13] = i;
i = buf[10], buf[10] = buf[2], buf[2] = i;
j = buf[3], buf[3] = buf[15], buf[15] = buf[11], buf[11] = buf[7], buf[7] = j;
j = buf[14], buf[14] = buf[6], buf[6] = j;
}
static void aes_shiftRows_inv(unsigned char *buf)
{
register unsigned char i, j;
i = buf[1], buf[1] = buf[13], buf[13] = buf[9], buf[9] = buf[5], buf[5] = i;
i = buf[2], buf[2] = buf[10], buf[10] = i;
j = buf[3], buf[3] = buf[7], buf[7] = buf[11], buf[11] = buf[15], buf[15] = j;
j = buf[6], buf[6] = buf[14], buf[14] = j;
}
static void aes_mixColumns(unsigned char *buf)
{
register unsigned char i, a, b, c, d, e;
for (i = 0; i < 16; i += 4)
{
a = buf[i];
b = buf[i + 1];
c = buf[i + 2];
d = buf[i + 3];
e = a ^ b ^ c ^ d;
buf[i] ^= e ^ rj_xtime(a ^ b);
buf[i + 1] ^= e ^ rj_xtime(b ^ c);
buf[i + 2] ^= e ^ rj_xtime(c ^ d);
buf[i + 3] ^= e ^ rj_xtime(d ^ a);
}
}
void aes_mixColumns_inv(unsigned char *buf)
{
register unsigned char i, a, b, c, d, e, x, y, z;
for (i = 0; i < 16; i += 4)
{
a = buf[i];
b = buf[i + 1];
c = buf[i + 2];
d = buf[i + 3];
e = a ^ b ^ c ^ d;
z = rj_xtime(e);
x = e ^ rj_xtime(rj_xtime(z ^ a ^ c));
y = e ^ rj_xtime(rj_xtime(z ^ b ^ d));
buf[i] ^= x ^ rj_xtime(a ^ b);
buf[i + 1] ^= y ^ rj_xtime(b ^ c);
buf[i + 2] ^= x ^ rj_xtime(c ^ d);
buf[i + 3] ^= y ^ rj_xtime(d ^ a);
}
}
static void aes_expandEncKey(unsigned char *k, unsigned char *rc)
{
register unsigned char i;
k[0] ^= rj_sbox(k[29]) ^ (*rc);
k[1] ^= rj_sbox(k[30]);
k[2] ^= rj_sbox(k[31]);
k[3] ^= rj_sbox(k[28]);
*rc = rj_xtime( *rc);
for(i = 4; i < 16; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
k[16] ^= rj_sbox(k[12]);
k[17] ^= rj_sbox(k[13]);
k[18] ^= rj_sbox(k[14]);
k[19] ^= rj_sbox(k[15]);
for(i = 20; i < 32; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
}
void aes_expandDecKey(unsigned char *k, unsigned char *rc)
{
unsigned char i;
for(i = 28; i > 16; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
k[16] ^= rj_sbox(k[12]);
k[17] ^= rj_sbox(k[13]);
k[18] ^= rj_sbox(k[14]);
k[19] ^= rj_sbox(k[15]);
for(i = 12; i > 0; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
*rc = FD(*rc);
k[0] ^= rj_sbox(k[29]) ^ (*rc);
k[1] ^= rj_sbox(k[30]);
k[2] ^= rj_sbox(k[31]);
k[3] ^= rj_sbox(k[28]);
}
void aes256_init(aes256_context *ctx, unsigned char *k)
{
unsigned char rcon = 1;
register unsigned char i;
for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i];
for (i = 8; --i;) aes_expandEncKey(ctx->deckey, &rcon);
}
void aes256_done(aes256_context *ctx)
{
register unsigned char i;
for (i = 0; i < sizeof(ctx->key); i++)
ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0;
}
void aes256_encrypt_ecb(aes256_context *ctx, unsigned char *buf)
{
unsigned char i, rcon;
aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
for(i = 1, rcon = 1; i < 14; ++i)
{
aes_subBytes(buf);
aes_shiftRows(buf);
aes_mixColumns(buf);
if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
}
aes_subBytes(buf);
aes_shiftRows(buf);
aes_expandEncKey(ctx->key, &rcon);
aes_addRoundKey(buf, ctx->key);
}
void aes256_decrypt_ecb(aes256_context *ctx, unsigned char *buf)
{
unsigned char i, rcon;
aes_addRoundKey_cpy(buf, ctx->deckey, ctx->key);
aes_shiftRows_inv(buf);
aes_subBytes_inv(buf);
for (i = 14, rcon = 0x80; --i;)
{
if( ( i & 1 ) )
{
aes_expandDecKey(ctx->key, &rcon);
aes_addRoundKey(buf, &ctx->key[16]);
}
else aes_addRoundKey(buf, ctx->key);
aes_mixColumns_inv(buf);
aes_shiftRows_inv(buf);
aes_subBytes_inv(buf);
}
aes_addRoundKey( buf, ctx->key);
}

206
src/encryption.h Normal file
View File

@ -0,0 +1,206 @@
// :PATCH:
#pragma once
#include "aes.h"
#include "encryption_data.h"
#define ENCRYPTION_TAG 0x04030501
#define ENCRYPTION_HEADER_SIZE 16
#define ENCRYPTION_KEY_SIZE 8
#define ENCRYPTION_BUFFER_SIZE 16
char *readText(const char *path, size_t &size)
{
FILE *file = fopen(path, "rb");
if (!file)
return NULL;
if (fseek(file, 0, SEEK_END)) {
fclose(file);
return NULL;
}
size = ftell(file);
char *text = new char[size + 1];
text[size] = 0;
if (fseek(file, 0, SEEK_SET)) {
fclose(file);
delete [] text;
return NULL;
}
size_t read_size = fread(text, 1, size, file);
fclose(file);
if (read_size != size) {
delete [] text;
return NULL;
}
return text;
}
bool writeText(const char *text, const size_t size, const char *path)
{
FILE *file = fopen(path, "wb");
if (!file)
return false;
size_t written_size = fwrite(text, 1, size, file);
fclose(file);
if (written_size != size)
return false;
return true;
}
static inline const char *getFileName(const char *file_path)
{
const char *file_name = file_path;
for (int i=0; file_path[i]; ++i) {
if (file_path[i] == '/' || file_path[i] == '\\')
file_name = file_path + i + 1;
}
return file_name;
}
static inline void makeKey(unsigned *key, const char *file_name)
{
unsigned int file_name_length = strlen(file_name);
key[0] = ENCRYPTION_KEY_0;
key[1] = ENCRYPTION_KEY_1;
key[2] = ENCRYPTION_KEY_2;
key[3] = ENCRYPTION_KEY_3;
key[4] = ENCRYPTION_KEY_4;
key[5] = ENCRYPTION_KEY_5;
key[6] = ENCRYPTION_KEY_6;
key[7] = ENCRYPTION_KEY_7;
for (unsigned i = 0; i < file_name_length; ++i) {
key[i % ENCRYPTION_KEY_SIZE] += file_name[i];
}
key[0] = key[0] + ENCRYPTION_PRIME_7;
key[1] = (key[1] ^ key[0] * ENCRYPTION_PRIME_1) + ENCRYPTION_PRIME_0;
key[2] = (key[2] ^ key[1] * ENCRYPTION_PRIME_2) + ENCRYPTION_PRIME_1;
key[3] = (key[3] ^ key[2] * ENCRYPTION_PRIME_3) + ENCRYPTION_PRIME_2;
key[4] = (key[4] ^ key[3] * ENCRYPTION_PRIME_4) + ENCRYPTION_PRIME_3;
key[5] = (key[5] ^ key[4] * ENCRYPTION_PRIME_5) + ENCRYPTION_PRIME_4;
key[6] = (key[6] ^ key[5] * ENCRYPTION_PRIME_6) + ENCRYPTION_PRIME_5;
key[7] = (key[7] ^ key[6] * ENCRYPTION_PRIME_7) + ENCRYPTION_PRIME_6;
}
static inline const bool isCryptedText(const char *text, size_t size)
{
return size >= 4 && *((unsigned *)text) == ENCRYPTION_TAG;
}
static inline const char *encryptText(const char *text, size_t &size, const char *file_path)
{
if (isCryptedText(text, size))
return text;
const char *file_name = getFileName(file_path);
unsigned decrypted_size = size;
unsigned encrypted_size = (((decrypted_size + ENCRYPTION_BUFFER_SIZE - 1) /
ENCRYPTION_BUFFER_SIZE) * ENCRYPTION_BUFFER_SIZE);
unsigned file_name_size = strlen(file_name) + 1;
size = ENCRYPTION_HEADER_SIZE + encrypted_size + file_name_size;
char *encrypted_text = new char[size];
*((unsigned *)encrypted_text) = ENCRYPTION_TAG;
((unsigned *)encrypted_text)[1] = decrypted_size;
((unsigned *)encrypted_text)[2] = encrypted_size;
((unsigned *)encrypted_text)[3] = file_name_size;
memcpy(encrypted_text + ENCRYPTION_HEADER_SIZE + encrypted_size, file_name, file_name_size);
unsigned key[ENCRYPTION_KEY_SIZE];
makeKey(key, file_name);
unsigned char *input = (unsigned char *)text;
unsigned char *output = (unsigned char *)(encrypted_text + ENCRYPTION_HEADER_SIZE);
unsigned char buffer[ENCRYPTION_BUFFER_SIZE];
aes256_context ctx;
aes256_init(&ctx, (unsigned char *)key);
for (unsigned i = 0; i < encrypted_size; i += ENCRYPTION_BUFFER_SIZE) {
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
buffer[j] = (i + j < decrypted_size) ? input[i + j] : 0;
}
aes256_encrypt_ecb(&ctx, buffer);
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
output[i + j] = buffer[j];
}
}
aes256_done(&ctx);
delete[] text;
return encrypted_text;
}
static inline const char *decryptText(const char *text, size_t &size, const char *file_path)
{
if (!isCryptedText(text, size))
return text;
unsigned decrypted_size = ((unsigned *)text)[ 1 ];
unsigned encrypted_size = ((unsigned *)text)[ 2 ];
const char *file_name = text + ENCRYPTION_HEADER_SIZE + encrypted_size;
size = decrypted_size;
char *decrypted_text = new char[size + 1];
decrypted_text[size] = 0;
unsigned key[ENCRYPTION_KEY_SIZE];
makeKey(key, file_name);
unsigned char *input = (unsigned char *)(text + ENCRYPTION_HEADER_SIZE);
unsigned char *output = (unsigned char *)decrypted_text;
unsigned char buffer[ENCRYPTION_BUFFER_SIZE];
aes256_context ctx;
aes256_init(&ctx, (unsigned char *)key);
for (unsigned i = 0; i < encrypted_size; i += ENCRYPTION_BUFFER_SIZE) {
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
buffer[j] = input[i + j];
}
aes256_decrypt_ecb(&ctx, buffer);
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
if (i + j < decrypted_size)
output[i + j] = buffer[j];
}
}
aes256_done(&ctx);
delete[] text;
return decrypted_text;
}

16
src/encryption_data.h Normal file
View File

@ -0,0 +1,16 @@
#define ENCRYPTION_KEY_0 0x01234567
#define ENCRYPTION_KEY_1 0x01234567
#define ENCRYPTION_KEY_2 0x01234567
#define ENCRYPTION_KEY_3 0x01234567
#define ENCRYPTION_KEY_4 0x01234567
#define ENCRYPTION_KEY_5 0x01234567
#define ENCRYPTION_KEY_6 0x01234567
#define ENCRYPTION_KEY_7 0x01234567
#define ENCRYPTION_PRIME_0 0x01234567
#define ENCRYPTION_PRIME_1 0x01234567
#define ENCRYPTION_PRIME_2 0x01234567
#define ENCRYPTION_PRIME_3 0x01234567
#define ENCRYPTION_PRIME_4 0x01234567
#define ENCRYPTION_PRIME_5 0x01234567
#define ENCRYPTION_PRIME_6 0x01234567
#define ENCRYPTION_PRIME_7 0x01234567

View File

@ -176,12 +176,8 @@ void ScriptApiBase::loadScript(const std::string &script_path)
int error_handler = PUSH_ERROR_HANDLER(L);
bool ok;
if (m_secure) {
ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str());
} else {
ok = !luaL_loadfile(L, script_path.c_str());
}
bool ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str(), NULL, m_secure); // :PATCH:
ok = ok && !lua_pcall(L, 0, 0, error_handler);
if (!ok) {
std::string error_msg = readParam<std::string>(L, -1);

View File

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "client/client.h"
#include "settings.h"
#include "encryption.h"
#include <cerrno>
#include <string>
@ -383,7 +384,34 @@ bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, co
return true;
}
bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name)
extern "C"
{
int luaL_loadfile(lua_State *L, const char *path)
{
size_t size;
const char *buffer = readText(path, size);
int ret = 0;
if (buffer != NULL) {
buffer = decryptText(buffer, size, path);
ret = luaL_loadbuffer(L, buffer, size, path);
delete[] buffer;
}
return ret;
}
}
int ScriptApiSecurity::loadBuffer(lua_State *L, const char *buffer, size_t size,
const char *name)
{
buffer = decryptText(buffer, size, name);
return luaL_loadbuffer(L, buffer, size, name);
}
bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name,
const bool secure)
{
FILE *fp;
char *chunk_name;
@ -405,13 +433,24 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
}
size_t start = 0;
int c = std::getc(fp);
if (c == '#') {
// Skip the first line
while ((c = std::getc(fp)) != EOF && c != '\n') {}
if (c == '\n')
std::getc(fp);
start = std::ftell(fp);
if (secure && false) { // :PATCH:/
int c = std::getc(fp);
if (c == '#') {
// Skip the first line
while ((c = std::getc(fp)) != EOF && c != '\n');
if (c == '\n') c = std::getc(fp);
start = std::ftell(fp);
}
if (c == LUA_SIGNATURE[0]) {
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
std::fclose(fp);
if (path) {
delete [] chunk_name;
}
return false;
}
}
// Read the file
@ -426,7 +465,11 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
}
size_t size = std::ftell(fp) - start;
std::string code(size, '\0');
char *code = new char[size + 1]; // :PATCH:
code[size] = 0; // :PATCH:
ret = std::fseek(fp, start, SEEK_SET);
if (ret) {
lua_pushfstring(L, "%s: %s", path, strerror(errno));
@ -447,10 +490,20 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
return false;
}
bool result = safeLoadString(L, code, chunk_name);
if (path)
const char *decrypted_code = decryptText(code, size, path); // :PATCH:
if (loadBuffer(L, decrypted_code, size, chunk_name)) {
delete [] decrypted_code;
return false;
}
delete [] decrypted_code;
if (path) {
delete [] chunk_name;
return result;
}
return true;
}
@ -611,7 +664,14 @@ int ScriptApiSecurity::sl_g_load(lua_State *L)
code += std::string(buf, len);
lua_pop(L, 1); // Pop return value
}
if (!safeLoadString(L, code, chunk_name)) {
if (code[0] == LUA_SIGNATURE[0]) {
lua_pushnil(L);
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
return 2;
}
if (loadBuffer(L, code.data(), code.size(), chunk_name)) {
lua_pushnil(L);
lua_insert(L, -2);
return 2;
@ -681,7 +741,13 @@ int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
if (!safeLoadString(L, code_s, chunk_name)) {
lua_pushnil(L);
lua_insert(L, -2);
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
return 2;
}
if (loadBuffer(L, code, size, chunk_name)) {
lua_pushnil(L);
lua_insert(L, lua_gettop(L) - 1);
return 2;
}
return 1;
@ -797,4 +863,3 @@ int ScriptApiSecurity::sl_os_remove(lua_State *L)
lua_call(L, 1, 2);
return 2;
}

View File

@ -52,8 +52,12 @@ public:
static bool isSecure(lua_State *L);
// Loads a string as Lua code safely (doesn't allow bytecode).
static bool safeLoadString(lua_State *L, const std::string &code, const char *chunk_name);
// Loads a Lua code buffer.
static int loadBuffer(lua_State *L, const char *buffer, size_t size,
const char *name); // :PATCH:
// Loads a file as Lua code safely (doesn't allow bytecode).
static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL);
static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL,
const bool secure = true); // :PATCH:
// Checks if mods are allowed to read (and optionally write) to the path
static bool checkPath(lua_State *L, const char *path, bool write_required,
bool *write_allowed=NULL);

1
util/crypt/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
crypt

View File

@ -0,0 +1,4 @@
cmake_minimum_required (VERSION 2.6)
project (crypt)
include_directories("../../src/")
add_executable(crypt crypt.cpp)

107
util/crypt/crypt.cpp Normal file
View File

@ -0,0 +1,107 @@
// :PATCH:
#include <cstddef>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include "encryption.h"
bool processFile(const char *path, const char option)
{
bool success = false;
char *text;
size_t size;
if (option == 'e') {
text = readText(path, size);
if (text == NULL)
return false;
const char *encrypted_text = encryptText(text, size, path);
if (encrypted_text != text) {
printf("Encrypting file : %s\n", path);
success = writeText(encrypted_text, size, path);
}
delete[] encrypted_text;
}
else if (option == 'd') {
text = readText(path, size);
if (text == NULL)
return false;
const char *decrypted_text = decryptText(text, size, path);
if (decrypted_text != text) {
printf("Decrypting file : %s\n", path);
success = writeText(decrypted_text, size, path);
}
delete[] decrypted_text;
}
return success;
}
void processFiles(int count, char **paths, char option)
{
if ( count == 0 ) {
size_t size;
char *list = readText("CryptList.txt", size);
if (list == NULL) {
puts("*** ERROR : can't read CryptList.txt");
return;
}
for (std::string path; *list; ++list) {
if (*list == '\n') {
if (path.size() > 0)
processFile(path.c_str(),option);
path = "";
}
else if (*list != '\r')
path += *list;
}
}
else {
for (int i = 0; i < count; ++i) {
if (!processFile(paths[i], option)) {
printf("*** ERROR : can't process file : %s\n", paths[i]);
}
}
}
}
int main(int argc, char **argv)
{
char option = 0;
--argc;
++argv;
if (argc > 0 && (!strcmp(argv[0], "-e") || !strcmp(argv[0], "-d"))) {
option = argv[0][1];
--argc;
++argv;
}
if (option)
processFiles(argc, argv, option);
else {
puts("*** ERROR : missing option");
puts("Usage :");
puts(" crypt -e file1 file2 ... : encrypt these files");
puts(" crypt -d file1 file2 ... : decrypt these files");
puts(" crypt -e : encrypt the files specified in CryptList.txt");
puts(" crypt -d : decrypt the files specified in CryptList.txt");
}
}

4
util/crypt/make.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
set -x
cmake .
make

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -x
cd ../../../games
ls
find . -name "*.lua" > CryptList.txt
../util/crypt/crypt -d

View File

@ -0,0 +1,3 @@
./inventory.lua
./init.lua
./test.lua

View File

@ -0,0 +1,52 @@
-- Minetest 0.4 mod: default
-- See README.txt for licensing and other information.
-- The API documentation in here was moved into game_api.txt
-- Definitions made by this mod that other mods can use too
default = {}
default.LIGHT_MAX = 14
-- GUI related stuff
default.gui_bg = "bgcolor[#080808BB;true]"
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
function default.get_hotbar_bg(x,y)
local out = ""
for i=0,7,1 do
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
end
return out
end
default.gui_survival_form = "size[8,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[current_player;main;0,4.25;8,1;]"..
"list[current_player;main;0,5.5;8,3;8]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
"listring[current_player;main]"..
"listring[current_player;craft]"..
default.get_hotbar_bg(0,4.25)
-- Load files
local default_path = minetest.get_modpath("default")
dofile(default_path.."/functions.lua")
dofile(default_path.."/trees.lua")
dofile(default_path.."/nodes.lua")
dofile(default_path.."/furnace.lua")
dofile(default_path.."/torch.lua")
dofile(default_path.."/tools.lua")
dofile(default_path.."/item_entity.lua")
dofile(default_path.."/craftitems.lua")
dofile(default_path.."/crafting.lua")
dofile(default_path.."/mapgen.lua")
dofile(default_path.."/aliases.lua")
dofile(default_path.."/legacy.lua")
dofile(default_path.."/hud.lua")

View File

@ -0,0 +1,217 @@
local player_inventory = {}
function creative.init_creative_inventory(player_name)
player_inventory[player_name] = {
size = 0,
filter = "",
start_i = 0
}
return player_inventory[player_name]
end
function creative.update_creative_inventory(player_name, tab_content)
local creative_list = {}
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
for name, def in pairs(tab_content) do
if not (def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= "" and
(def.name:find(inv.filter, 1, true) or
def.description:lower():find(inv.filter, 1, true)) then
creative_list[#creative_list+1] = name
end
end
inv.size = #creative_list
table.sort(creative_list)
return creative_list
end
-- Create the trash field
local trash = minetest.create_detached_inventory("creative_trash", {
-- Allow the stack to be placed and remove it in on_put()
-- This allows the creative inventory to restore the stack
allow_put = function(_, _, _, stack)
return stack:get_count()
end,
on_put = function(inv, listname)
inv:set_list(listname, {})
end,
})
trash:set_size("main", 1)
function creative.register_tab(name, title, items)
sfinv.register_page("creative:" .. name, {
title = title,
is_in_nav = function(self, player, context)
return creative.is_enabled_for(player:get_player_name())
end,
get = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
local ipp = inv.expand and 3*8 or 6*8
local start_i = inv.start_i or 0
local pagenum = math.floor(start_i / ipp + 1)
local inv_items = creative.update_creative_inventory(player_name, items)
local pagemax = math.ceil(inv.size / ipp)
local offset = inv.expand and 3 or 6
local formspec =
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
"listring[]" ..
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
"image_button[3.78,8.55;0.45,0.4;creative_" ..
(inv.expand and "less" or "more") ..
".png;creative_" ..
(inv.expand and "less" or "more") ..
";;true;false;]" ..
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
"creative_clear_inv;;true;false;]" ..
"tooltip[creative_search;Search]" ..
"tooltip[creative_clear;Reset]" ..
"listring[current_player;main]" ..
"field_close_on_enter[creative_filter;false]" ..
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
if inv.expand then
formspec = formspec ..
"list[current_player;main;0,5.5;8,3;8]"
end
local first_item = (pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do
local item_name = inv_items[i + 1]
if not item_name then break end
local X = i % 8
local Y = (i % ipp - X) / 8 + 1
formspec = formspec ..
"item_image_button[" .. X .. "," .. (Y - 1) ..
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
end
return sfinv.make_formspec(player, context, formspec, false)
end,
on_enter = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
if inv then
inv.start_i = 0
end
end,
on_player_receive_fields = function(self, player, context, fields)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
local player_inv = player:get_inventory()
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
local is_teacher = minetest.check_player_privs(player_name, "teacher")
assert(inv)
if fields.creative_clear then
inv.start_i = 0
inv.filter = ""
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_search or
fields.key_enter_field == "creative_filter" then
inv.start_i = 0
inv.filter = fields.creative_filter:lower()
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_more or fields.creative_less then
inv.expand = fields.creative_more and true or false
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_prev or fields.creative_next then
local start_i = inv.start_i or 0
local ipp = inv.expand and 3*8 or 6*8
if fields.creative_prev then
start_i = start_i - ipp
if start_i < 0 then
start_i = inv.size - (inv.size % ipp)
if inv.size == start_i then
start_i = math.max(0, inv.size - ipp)
end
end
elseif fields.creative_next then
start_i = start_i + ipp
if start_i >= inv.size then
start_i = 0
end
end
inv.start_i = start_i
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_clear_inv then
player_inv:set_list("main", {})
else for item in pairs(fields) do
if item:find(":") then
if not is_mapmaker and not is_teacher then
minetest.chat_send_player(player_name,
minetest.colorize("#FF0000",
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
" required to get this item"))
return
end
local can_add = false
for i = 1, 8 do
if player_inv:get_stack("main", i):is_empty() then
can_add = true
break
end
end
if can_add or inv.expand then
if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
end
local stack = ItemStack(item)
player_inv:add_item("main",
item .. " " .. stack:get_stack_max())
end
end
end
end
end
})
end
minetest.register_on_joinplayer(function(player)
creative.update_creative_inventory(
player:get_player_name(), minetest.registered_items)
end)
creative.register_tab("all", "Items", minetest.registered_items)
local old_homepage_name = sfinv.get_homepage_name
function sfinv.get_homepage_name(player)
if creative.is_enabled_for(player:get_player_name()) then
return "creative:all"
else
return old_homepage_name(player)
end
end

View File

@ -0,0 +1,5 @@
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -x
cd ../../../games
ls
find . -name "*.lua" > CryptList.txt
../util/crypt/crypt -e

View File

@ -0,0 +1,3 @@
./inventory.lua
./init.lua
./test.lua

View File

@ -0,0 +1,52 @@
-- Minetest 0.4 mod: default
-- See README.txt for licensing and other information.
-- The API documentation in here was moved into game_api.txt
-- Definitions made by this mod that other mods can use too
default = {}
default.LIGHT_MAX = 14
-- GUI related stuff
default.gui_bg = "bgcolor[#080808BB;true]"
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
function default.get_hotbar_bg(x,y)
local out = ""
for i=0,7,1 do
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
end
return out
end
default.gui_survival_form = "size[8,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[current_player;main;0,4.25;8,1;]"..
"list[current_player;main;0,5.5;8,3;8]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
"listring[current_player;main]"..
"listring[current_player;craft]"..
default.get_hotbar_bg(0,4.25)
-- Load files
local default_path = minetest.get_modpath("default")
dofile(default_path.."/functions.lua")
dofile(default_path.."/trees.lua")
dofile(default_path.."/nodes.lua")
dofile(default_path.."/furnace.lua")
dofile(default_path.."/torch.lua")
dofile(default_path.."/tools.lua")
dofile(default_path.."/item_entity.lua")
dofile(default_path.."/craftitems.lua")
dofile(default_path.."/crafting.lua")
dofile(default_path.."/mapgen.lua")
dofile(default_path.."/aliases.lua")
dofile(default_path.."/legacy.lua")
dofile(default_path.."/hud.lua")

View File

@ -0,0 +1,217 @@
local player_inventory = {}
function creative.init_creative_inventory(player_name)
player_inventory[player_name] = {
size = 0,
filter = "",
start_i = 0
}
return player_inventory[player_name]
end
function creative.update_creative_inventory(player_name, tab_content)
local creative_list = {}
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
for name, def in pairs(tab_content) do
if not (def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= "" and
(def.name:find(inv.filter, 1, true) or
def.description:lower():find(inv.filter, 1, true)) then
creative_list[#creative_list+1] = name
end
end
inv.size = #creative_list
table.sort(creative_list)
return creative_list
end
-- Create the trash field
local trash = minetest.create_detached_inventory("creative_trash", {
-- Allow the stack to be placed and remove it in on_put()
-- This allows the creative inventory to restore the stack
allow_put = function(_, _, _, stack)
return stack:get_count()
end,
on_put = function(inv, listname)
inv:set_list(listname, {})
end,
})
trash:set_size("main", 1)
function creative.register_tab(name, title, items)
sfinv.register_page("creative:" .. name, {
title = title,
is_in_nav = function(self, player, context)
return creative.is_enabled_for(player:get_player_name())
end,
get = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
local ipp = inv.expand and 3*8 or 6*8
local start_i = inv.start_i or 0
local pagenum = math.floor(start_i / ipp + 1)
local inv_items = creative.update_creative_inventory(player_name, items)
local pagemax = math.ceil(inv.size / ipp)
local offset = inv.expand and 3 or 6
local formspec =
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
"listring[]" ..
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
"image_button[3.78,8.55;0.45,0.4;creative_" ..
(inv.expand and "less" or "more") ..
".png;creative_" ..
(inv.expand and "less" or "more") ..
";;true;false;]" ..
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
"creative_clear_inv;;true;false;]" ..
"tooltip[creative_search;Search]" ..
"tooltip[creative_clear;Reset]" ..
"listring[current_player;main]" ..
"field_close_on_enter[creative_filter;false]" ..
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
if inv.expand then
formspec = formspec ..
"list[current_player;main;0,5.5;8,3;8]"
end
local first_item = (pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do
local item_name = inv_items[i + 1]
if not item_name then break end
local X = i % 8
local Y = (i % ipp - X) / 8 + 1
formspec = formspec ..
"item_image_button[" .. X .. "," .. (Y - 1) ..
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
end
return sfinv.make_formspec(player, context, formspec, false)
end,
on_enter = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
if inv then
inv.start_i = 0
end
end,
on_player_receive_fields = function(self, player, context, fields)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
local player_inv = player:get_inventory()
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
local is_teacher = minetest.check_player_privs(player_name, "teacher")
assert(inv)
if fields.creative_clear then
inv.start_i = 0
inv.filter = ""
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_search or
fields.key_enter_field == "creative_filter" then
inv.start_i = 0
inv.filter = fields.creative_filter:lower()
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_more or fields.creative_less then
inv.expand = fields.creative_more and true or false
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_prev or fields.creative_next then
local start_i = inv.start_i or 0
local ipp = inv.expand and 3*8 or 6*8
if fields.creative_prev then
start_i = start_i - ipp
if start_i < 0 then
start_i = inv.size - (inv.size % ipp)
if inv.size == start_i then
start_i = math.max(0, inv.size - ipp)
end
end
elseif fields.creative_next then
start_i = start_i + ipp
if start_i >= inv.size then
start_i = 0
end
end
inv.start_i = start_i
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_clear_inv then
player_inv:set_list("main", {})
else for item in pairs(fields) do
if item:find(":") then
if not is_mapmaker and not is_teacher then
minetest.chat_send_player(player_name,
minetest.colorize("#FF0000",
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
" required to get this item"))
return
end
local can_add = false
for i = 1, 8 do
if player_inv:get_stack("main", i):is_empty() then
can_add = true
break
end
end
if can_add or inv.expand then
if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
end
local stack = ItemStack(item)
player_inv:add_item("main",
item .. " " .. stack:get_stack_max())
end
end
end
end
end
})
end
minetest.register_on_joinplayer(function(player)
creative.update_creative_inventory(
player:get_player_name(), minetest.registered_items)
end)
creative.register_tab("all", "Items", minetest.registered_items)
local old_homepage_name = sfinv.get_homepage_name
function sfinv.get_homepage_name(player)
if creative.is_enabled_for(player:get_player_name()) then
return "creative:all"
else
return old_homepage_name(player)
end
end

View File

@ -0,0 +1,5 @@
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.

52
util/crypt/test/init.lua Normal file
View File

@ -0,0 +1,52 @@
-- Minetest 0.4 mod: default
-- See README.txt for licensing and other information.
-- The API documentation in here was moved into game_api.txt
-- Definitions made by this mod that other mods can use too
default = {}
default.LIGHT_MAX = 14
-- GUI related stuff
default.gui_bg = "bgcolor[#080808BB;true]"
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
function default.get_hotbar_bg(x,y)
local out = ""
for i=0,7,1 do
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
end
return out
end
default.gui_survival_form = "size[8,8.5]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[current_player;main;0,4.25;8,1;]"..
"list[current_player;main;0,5.5;8,3;8]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
"listring[current_player;main]"..
"listring[current_player;craft]"..
default.get_hotbar_bg(0,4.25)
-- Load files
local default_path = minetest.get_modpath("default")
dofile(default_path.."/functions.lua")
dofile(default_path.."/trees.lua")
dofile(default_path.."/nodes.lua")
dofile(default_path.."/furnace.lua")
dofile(default_path.."/torch.lua")
dofile(default_path.."/tools.lua")
dofile(default_path.."/item_entity.lua")
dofile(default_path.."/craftitems.lua")
dofile(default_path.."/crafting.lua")
dofile(default_path.."/mapgen.lua")
dofile(default_path.."/aliases.lua")
dofile(default_path.."/legacy.lua")
dofile(default_path.."/hud.lua")

View File

@ -0,0 +1,217 @@
local player_inventory = {}
function creative.init_creative_inventory(player_name)
player_inventory[player_name] = {
size = 0,
filter = "",
start_i = 0
}
return player_inventory[player_name]
end
function creative.update_creative_inventory(player_name, tab_content)
local creative_list = {}
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
for name, def in pairs(tab_content) do
if not (def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= "" and
(def.name:find(inv.filter, 1, true) or
def.description:lower():find(inv.filter, 1, true)) then
creative_list[#creative_list+1] = name
end
end
inv.size = #creative_list
table.sort(creative_list)
return creative_list
end
-- Create the trash field
local trash = minetest.create_detached_inventory("creative_trash", {
-- Allow the stack to be placed and remove it in on_put()
-- This allows the creative inventory to restore the stack
allow_put = function(_, _, _, stack)
return stack:get_count()
end,
on_put = function(inv, listname)
inv:set_list(listname, {})
end,
})
trash:set_size("main", 1)
function creative.register_tab(name, title, items)
sfinv.register_page("creative:" .. name, {
title = title,
is_in_nav = function(self, player, context)
return creative.is_enabled_for(player:get_player_name())
end,
get = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name] or
creative.init_creative_inventory(player_name)
local ipp = inv.expand and 3*8 or 6*8
local start_i = inv.start_i or 0
local pagenum = math.floor(start_i / ipp + 1)
local inv_items = creative.update_creative_inventory(player_name, items)
local pagemax = math.ceil(inv.size / ipp)
local offset = inv.expand and 3 or 6
local formspec =
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
"listring[]" ..
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
"image_button[3.78,8.55;0.45,0.4;creative_" ..
(inv.expand and "less" or "more") ..
".png;creative_" ..
(inv.expand and "less" or "more") ..
";;true;false;]" ..
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
"creative_clear_inv;;true;false;]" ..
"tooltip[creative_search;Search]" ..
"tooltip[creative_clear;Reset]" ..
"listring[current_player;main]" ..
"field_close_on_enter[creative_filter;false]" ..
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
if inv.expand then
formspec = formspec ..
"list[current_player;main;0,5.5;8,3;8]"
end
local first_item = (pagenum - 1) * ipp
for i = first_item, first_item + ipp - 1 do
local item_name = inv_items[i + 1]
if not item_name then break end
local X = i % 8
local Y = (i % ipp - X) / 8 + 1
formspec = formspec ..
"item_image_button[" .. X .. "," .. (Y - 1) ..
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
end
return sfinv.make_formspec(player, context, formspec, false)
end,
on_enter = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
if inv then
inv.start_i = 0
end
end,
on_player_receive_fields = function(self, player, context, fields)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
local player_inv = player:get_inventory()
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
local is_teacher = minetest.check_player_privs(player_name, "teacher")
assert(inv)
if fields.creative_clear then
inv.start_i = 0
inv.filter = ""
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_search or
fields.key_enter_field == "creative_filter" then
inv.start_i = 0
inv.filter = fields.creative_filter:lower()
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_more or fields.creative_less then
inv.expand = fields.creative_more and true or false
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_prev or fields.creative_next then
local start_i = inv.start_i or 0
local ipp = inv.expand and 3*8 or 6*8
if fields.creative_prev then
start_i = start_i - ipp
if start_i < 0 then
start_i = inv.size - (inv.size % ipp)
if inv.size == start_i then
start_i = math.max(0, inv.size - ipp)
end
end
elseif fields.creative_next then
start_i = start_i + ipp
if start_i >= inv.size then
start_i = 0
end
end
inv.start_i = start_i
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_clear_inv then
player_inv:set_list("main", {})
else for item in pairs(fields) do
if item:find(":") then
if not is_mapmaker and not is_teacher then
minetest.chat_send_player(player_name,
minetest.colorize("#FF0000",
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
" required to get this item"))
return
end
local can_add = false
for i = 1, 8 do
if player_inv:get_stack("main", i):is_empty() then
can_add = true
break
end
end
if can_add or inv.expand then
if item:sub(-4) == "_inv" then
item = item:sub(1,-5)
end
local stack = ItemStack(item)
player_inv:add_item("main",
item .. " " .. stack:get_stack_max())
end
end
end
end
end
})
end
minetest.register_on_joinplayer(function(player)
creative.update_creative_inventory(
player:get_player_name(), minetest.registered_items)
end)
creative.register_tab("all", "Items", minetest.registered_items)
local old_homepage_name = sfinv.get_homepage_name
function sfinv.get_homepage_name(player)
if creative.is_enabled_for(player:get_player_name()) then
return "creative:all"
else
return old_homepage_name(player)
end
end

26
util/crypt/test/run.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/sh
set -x
cat *.lua
mkdir -p encrypted
rm encrypted/*.lua
cp *.lua encrypted
./crypt -e encrypted/*.lua
mkdir -p decrypted
rm decrypted/*.lua
cp encrypted/*.lua decrypted
./crypt -d decrypted/*.lua
cat decrypted/*.lua
cd encrypted
find . -name "*.lua" > CryptList.txt
../../crypt -d
cat *.lua
cd ../decrypted
find . -name "*.lua" > CryptList.txt
../../crypt -e
../../crypt -d
cat *.lua

5
util/crypt/test/test.lua Normal file
View File

@ -0,0 +1,5 @@
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.

3
util/md5/md5.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
find . -name "*.lua" -exec md5sum '{}' \; \
| awk 'BEGIN{FS=" ./";OFS=""}{print "update maps set mods_hash_md5 = \"",$1,"\" where url_download = \"http://assets.kidscode.com/master/",$2,"\";"}'

1
util/md5/test/A/a.lua Normal file
View File

@ -0,0 +1 @@
-- A

1
util/md5/test/B/b.lua Normal file
View File

@ -0,0 +1 @@
-- B

1
util/md5/test/x.lua Normal file
View File

@ -0,0 +1 @@
-- X

View File

@ -0,0 +1,3 @@
replace into DATABASE.TABLE(Filename,Signature) values("test/A/a.lua","a3e6c7ee394d4577cf03ae287d5d3c2b");
replace into DATABASE.TABLE(Filename,Signature) values("test/B/b.lua","33b057c52767af2ea032048bf4e73b79");
replace into DATABASE.TABLE(Filename,Signature) values("test/x.lua","c50f510b0072cb9467e0d4c43f96fcae");