Giter Site home page Giter Site logo

pow-captcha's Introduction

PoW-captcha

A PoW-based captcha for your web application.

require

  • nodejs >= v12.16.0

How to use

Install

npm i @yalexin/pow-captcha

Usage

⚡You must design the server logic for the pow, and you can refer to API

Basic Usage

const Captcha = require("@yalexin/pow-captcha");
const [api1, api2] = ['http://server.com/powConfig', 'http://server.com/powVerify'];
Captcha.startPoW(api1, api2).then(res => {
    console.log(res);
}).catch(e => {
    console.log(e);
}
)

Advanced Usage

You may want to use your request object , such as axios

const Captcha = require("@yalexin/pow-captcha");
const [api1, api2] = ['http://server.com/powConfig', 'http://server.com/powVerify'];
Captcha.getPoWWithAxios(api1, this.$axios).then(config => {
    Captcha.tryPoWWithAxios(api2, config, this.$axios).then(verifyResult => {
        console.log('verifyResult = ', verifyResult);
    }).catch(e => {
        console.log(e);
    })
    }).catch(e => {
        console.log(e);
    }
)

⚡You must design the server logic for the pow

API

server

1. getConfig

In server,You must return json data in /powConfig

The format of return data may be like this:

{"difficulty":5,"prefix":"Ve03Plle"}

where difficultyindicates the difficulty of the pow puzzle and prefixindicates the random string.

The thing of client must to do is that find a paddingNum,which satisfies:

md5(prefix+string(paddingNum))=000...00xxxx

where the number of leading zeros at least difficulty.

For example with Java Spring Boot:

// @Controller
@GetMapping("/powConfig")
public ResponseEntity getPowConfig(HttpServletRequest request,
                                   HttpServletResponse response) {
    Map map = userService.getPowConfig(request, response);
    return new ResponseEntity(map, HttpStatus.OK);
}
// @Service
@Override
public Map getPowConfig(HttpServletRequest request, HttpServletResponse response) {
    String randomString = getRandomString(powPrefixLength);
    HashMap<Object, Object> hashMap = new HashMap<>();
    hashMap.put("prefix", randomString);
    hashMap.put("difficulty", powDifficulty);
    request.getSession().setAttribute("powConfig", hashMap);
    return hashMap;
}
private String getRandomString(int length) {
    String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    Random random = new Random();
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < length; i++) {
        int number = random.nextInt(62);
        sb.append(str.charAt(number));
    }
    return sb.toString();
}

2. powVerify

In /powVerify,you will get the data posted by client, where data likes:

{
    "data":{
        "md5Str":"00000119414c7a8c9678b96fbc4954be",
        "paddingNum":300880
    }
}

You must verify two things:

  1. md5Str==md5(prefix+paddingNum)
  2. The leading zeros of md5Strmust at least difficulty

difficulty and prefix correspond to the value you gave the client earlier.

For example with Java Spring Boot:

// @Controller
@PostMapping("/powVerify")
public ResponseEntity powVerify(HttpServletRequest request,
                                HttpServletResponse response, @RequestBody JSONObject json) {
    Map map = userService.verifyPow(request, response, json.getJSONObject("data"));
    return new ResponseEntity(map, HttpStatus.OK);
}
// @Service
public Map verifyPow(HttpServletRequest request, HttpServletResponse response, JSONObject json) {
    HttpSession session = request.getSession();
    try {
        HashMap powConfig = (HashMap) session.getAttribute("powConfig");

        String sessionPrefix = (String) powConfig.get("prefix");
        int difficulty = (int) powConfig.get("difficulty");
        String md5Str = (String) json.get("md5Str");
        int paddingNum = (int) json.get("paddingNum");

        String hashCode = MD5Utils.code(sessionPrefix + (paddingNum));
        // If the session has not generated a prefix, 
        // or if the prefix is empty, 
        // or if the hash value is incorrect, 
        // or if the complexity of the hash value is incorrect, 
        // the validation fails.
        if (sessionPrefix == null || "".equals(sessionPrefix) || !hashCode.equals(md5Str) || !checkHash(hashCode, difficulty)) {
            HashMap hashMap = new HashMap<>();
            hashMap.put("verify", false);
            // Re-generating random prefixes
            String randomString = getRandomString(powPrefixLength);
            hashMap.put("prefix", randomString);
            hashMap.put("difficulty", powDifficulty);
            session.setAttribute("powConfig", hashMap);
            return hashMap;
        } else {
            HashMap hashMap = new HashMap<>();
            hashMap.put("verify", true);
            session.setAttribute("powVerifyResult", true);
            return hashMap;
        }
    } catch (NullPointerException e) {
        HashMap hashMap = new HashMap<>();
        hashMap.put("verify", false);
        // Re-generating random prefixes
        String randomString = getRandomString(powPrefixLength);
        hashMap.put("prefix", randomString);
        hashMap.put("difficulty", powDifficulty);
        session.setAttribute("powConfig", hashMap);
        return hashMap;
    }

}
private boolean checkHash(String hashStr, int difficulty) {
    int zeroCnt = 0;
    for (int idx = 0; idx < difficulty; idx++) {
        if (hashStr.charAt(idx) != '0') break;
        zeroCnt++;
    }
    return zeroCnt >= difficulty;
}

You can get more detail about the server logic form my repository

client

Captcha.startPoW() and Captcha.tryPoWWithAxios() will return a object if pow-process is success.

{
    verify: true, 
    totalTryCnt: totalTryCnt
}
field description
verify The result of server verify
totalTryCnt The total times of try to find paddingNum

pow-captcha's People

Contributors

yalexin avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.