#define _XOPEN_SOURCE #include #include #include #include #include #include using namespace v8; static char SECURE_SALT[21] = "$5$"; #define TRIP_MAX 128 void set_salt(const Nan::FunctionCallbackInfo& info) { if (info.Length() != 1) { Nan::ThrowTypeError("setSalt takes one argument"); return; } Nan::Utf8String saltVal(info[0]); if (saltVal.length() != 16) { Nan::ThrowTypeError("setSalt takes a string of length 16"); return; } char *salt = *saltVal; if (!salt) { Nan::ThrowTypeError("setSalt read a null string?!"); return; } memcpy(SECURE_SALT + 3, salt, 16); SECURE_SALT[19] = '$'; SECURE_SALT[20] = 0; info.GetReturnValue().Set(true); } static void fix_char(char &c) { static const char *from = ":;<=>?@[\\]^_`", *to = "ABCDEFGabcdef"; const char *p; if (c < '.' || c > 'z') c = '.'; else if ((p = strchr(from, c))) c = to[p - from]; } static void hash_trip(char *key, size_t len, char *dest) { char *digest, salt[3] = ".."; if (len == 1) salt[0] = 'H'; else if (len == 2) { salt[0] = key[1]; salt[1] = 'H'; } else if (len) strncpy(salt, key + 1, 2); fix_char(salt[0]); fix_char(salt[1]); digest = crypt(key, salt); if (!digest) return; len = strlen(digest); if (len < 11) return; digest += len - 11; digest[0] = '!'; strncpy(dest, digest, 12); } static void hash_secure(char *key, size_t len, char *dest) { size_t i; char *digest; if (len > TRIP_MAX) { len = TRIP_MAX; key[TRIP_MAX] = 0; } for (i = 0; i < len; i++) fix_char(key[i]); digest = crypt(key, SECURE_SALT); if (!digest) return; len = strlen(digest); if (len < 12) return; digest += len - 12; digest[0] = digest[1] = '!'; strncpy(dest, digest, 13); } static iconv_t conv_desc; static int setup_conv() { conv_desc = iconv_open("SHIFT_JIS", "UTF-8"); if (conv_desc == (iconv_t) -1) { fprintf(stderr, "Can't convert to SHIFT_JIS.\n"); return 0; } return 1; } typedef void (*trip_f)(char *, size_t, char *); static void with_SJIS(Nan::Utf8String &trip, trip_f func, char *ret) { char *src = *trip; if (!src) return; size_t src_left = trip.length(), dest_left = TRIP_MAX; if (!src_left) return; if (src_left > TRIP_MAX / 2) src_left = TRIP_MAX / 2; char sjis[TRIP_MAX+1]; char *dest = sjis; size_t result = iconv(conv_desc, &src, &src_left, &dest, &dest_left); if (result == (size_t) -1 && errno != EILSEQ && errno != EINVAL) { perror("iconv"); return; } ssize_t len = TRIP_MAX - dest_left; if (len > 0) { sjis[len] = 0; func(sjis, len, ret); } } void hash(const Nan::FunctionCallbackInfo& info) { if (info.Length() != 2) { Nan::ThrowTypeError("hash takes 2 arguments"); return; } Nan::Utf8String trip(info[0]), secure(info[1]); char digest[24]; digest[0] = 0; with_SJIS(trip, &hash_trip, digest); with_SJIS(secure, &hash_secure, digest + strlen(digest)); Local digest_str = Nan::New(digest).ToLocalChecked(); info.GetReturnValue().Set(digest_str); } void init(Local exports) { if (!setup_conv()) return; exports->Set(Nan::New("setSalt").ToLocalChecked(), Nan::New(set_salt)->GetFunction()); exports->Set(Nan::New("hash").ToLocalChecked(), Nan::New(hash)->GetFunction()); } NODE_MODULE(tripcode, init)