npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cowherd

v1.1.8

Published

Automatic token issuer help create upload/download tokens for Qiniu CDN service.

Downloads

15

Readme

Cowherd

Cowherd is an automatic token issuer help create upload/download tokens for Qiniu CDN service in Node.js.

Install cowherd from NPM registry

npm install --save cowherd

Usage

Create a new Node.js project

npm init

Edit index.js:

var cowherd = require('cowherd');

cowherd({
    accessKey: "YOUR_ACCESS_KEY",
    secretKey: "YOUR_SECRET_KEY",
    callbackUrl: "http://example.com/:callback", // publicly accessible callback address

    bucket: "qtest",

    autoKeyNaming: require('cowherd/strategy/sha1'),

    routes: [
        {
            match: '/avatars',
            policy: {
                mimeLimit: "image/*"
                fsizeLimit: 204800 // Limit avatar file to 200kb
            }
        }, {
            match: '/photos',
            policy: {
                mimeLimit: "image/*"
            }
        }
    ]
}).listen(8020, '::', function () {
    console.log('Qiniu uptoken service started');
});

Run index.js and send POST request to http://localhost:8020/avatars to generate an "uptoken". The key of uploaded file is decided by autoKeyNaming function (sha1 checksum of uploaded file for example).

How it works

Cowherd is configured to generate upload token in callbackFetchKey mode (see documentation).

{
    "scope": "<bucket>",
    "deadline": 1466701046,
    "fsizeMin": 0,
    "fsizeLimit": 4194304,
    "detectMime": 1,
    "callbackFetchKey": 1,
    "callbackBodyType": "application/json",
    "callbackBody": "<json-string-template>",
    "callbackUrl": "http://example.com/_callbacks/526a60b6968609e7926c1683cf869895"
}

After file is uploaded to Qiniu, callbackUrl is called. callbackBody is collected and passed to route's autoKeyNaming function to decide the key of uploaded file (see strategy/sha1.js for details).

Download Token

Download token is required to access resource from Qiniu private bucket. Add a get object to route config object:

var utils = require('cowherd/utils');

cowherd({
    // ...
    routes: [
        {
            match: '/photos',
            policy: {
                mimeLimit: "image/*"
            },
            get: {
                deadline: utils.expiresIn(3600) // Optional, expiration time function
            }
        },
        // ...
    ]
}).listen(...);

Send a GET request to /photos?url=http%3A%2F%2F78re52.com1.z0.glb.clouddn.com%2Fresource%2Fflower.jpg should generates a download token for http://78re52.com1.z0.glb.clouddn.com/resource/flower.jpg expires in 3600 seconds.

Advanced Usage

Authentication

Authentication is implemented in standard connect middleware style. Here's an implementation of JWT authentication:

// simple JWT authenticator
var jwt = require('jwt-simple');
var jwtAuthenticator = (req, res, ctx, next) => {
    try {
        var token = jwt.decode(req.headers["authorization"], process.env.JWT_SECRET, false, process.env.JWT_MODE);
        if (Date.now() > token.expires_at * 1000) {
          return res.status(401).send();
        }
        return next();
    } catch (e) {
        return res.status(401).send();
    }
};

cowherd({
    // ...
    routes: [
        {
            match: '/photos',
            authenticator: jwtAuthenticator,
            // ...
        }
    ]
}).listen(...);

Handle duplicate keys

Upload files with same content will callback with a same qetag. When using naming function generating filename from etag (eg, etag/sha1 naming function) Qiniu would throw an error to the upload client. A workaround is to return a different key to Qiniu and use naming function only in key returned to upload client.

Override callback function of policy object:

var request = require('request');

policy: {
    //...
    callback: (data, next) => {
      var url = `${DOMAIN_PREFIX}/${data.key}`;
      request.head(url, (err, res) => {
        if (err) {
          return next(err)
        }
        if (res.statusCode !== 404) {
          data.key = `.qn-shim/${data.key}-${data.payload.uuid}`;
        }
        return next(null, data);
      });
    }
}

The data object is a response object to Qiniu callback. data.key is key of uploaded file and data.payload will be sent to upload client. To avoid error on uploading same file, a simple check of key existence is applied and the key is re-written to .qn-shim/{key}-{uuid} (and the file is in bucket now).

It's recommended to setup some task to clean-up these files periodically.

Disable automatic key naming

Use a noop naming function:

cowherd({
    // ...
    autoKeyNaming: require('cowherd/strategy/noop'),
    // ...
}).listen(...);

License

(The MIT License)