You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
doushio/tripcode/tripcode.cc

149 lines
3.3 KiB

#define _XOPEN_SOURCE
#include <errno.h>
#include <iconv.h>
#include <unistd.h>
#include <nan.h>
#include <node.h>
#include <string.h>
using namespace v8;
static char SECURE_SALT[21] = "$5$";
#define TRIP_MAX 128
void set_salt(const Nan::FunctionCallbackInfo<Value>& 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<Value>& 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<String> digest_str = Nan::New(digest).ToLocalChecked();
info.GetReturnValue().Set(digest_str);
}
void init(Local<Object> exports) {
if (!setup_conv())
return;
exports->Set(Nan::New("setSalt").ToLocalChecked(),
Nan::New<FunctionTemplate>(set_salt)->GetFunction());
exports->Set(Nan::New("hash").ToLocalChecked(),
Nan::New<FunctionTemplate>(hash)->GetFunction());
}
NODE_MODULE(tripcode, init)