liuyuqi-dellpc 3 years ago
commit
41219bd90b

+ 8 - 0
README.md

@@ -0,0 +1,8 @@
+## wechat_sign
+
+JAVA, Node, Python 部分代码只实现了签名算法,需要开发者传入 jsapi_ticket 和 url ,其中 jsapi_ticket 需要通过 http://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=ACCESS_TOKEN 接口获取,url 为调用页面的完整 url 。
+
+PHP 部分代码包括了获取 access_token 和 jsapi_ticket 的操作,只需传入 appid 和 appsecret 即可,但要注意如果已有其他业务需要使用 access_token 的话,应修改获取 access_token 部分代码从全局缓存中获取,防止重复获取 access_token ,超过调用频率。
+
+注意事项:
+1. jsapi_ticket 的有效期为 7200 秒,开发者必须全局缓存 jsapi_ticket ,防止超过调用频率。

+ 78 - 0
java/sign.java

@@ -0,0 +1,78 @@
+import java.util.UUID;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Formatter;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.io.UnsupportedEncodingException;  
+
+class Sign {
+    public static void main(String[] args) {
+        String jsapi_ticket = "jsapi_ticket";
+
+        // 注意 URL 一定要动态获取,不能 hardcode
+        String url = "http://example.com";
+        Map<String, String> ret = sign(jsapi_ticket, url);
+        for (Map.Entry entry : ret.entrySet()) {
+            System.out.println(entry.getKey() + ", " + entry.getValue());
+        }
+    };
+
+    public static Map<String, String> sign(String jsapi_ticket, String url) {
+        Map<String, String> ret = new HashMap<String, String>();
+        String nonce_str = create_nonce_str();
+        String timestamp = create_timestamp();
+        String string1;
+        String signature = "";
+
+        //注意这里参数名必须全部小写,且必须有序
+        string1 = "jsapi_ticket=" + jsapi_ticket +
+                  "&noncestr=" + nonce_str +
+                  "&timestamp=" + timestamp +
+                  "&url=" + url;
+        System.out.println(string1);
+
+        try
+        {
+            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
+            crypt.reset();
+            crypt.update(string1.getBytes("UTF-8"));
+            signature = byteToHex(crypt.digest());
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            e.printStackTrace();
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            e.printStackTrace();
+        }
+
+        ret.put("url", url);
+        ret.put("jsapi_ticket", jsapi_ticket);
+        ret.put("nonceStr", nonce_str);
+        ret.put("timestamp", timestamp);
+        ret.put("signature", signature);
+
+        return ret;
+    }
+
+    private static String byteToHex(final byte[] hash) {
+        Formatter formatter = new Formatter();
+        for (byte b : hash)
+        {
+            formatter.format("%02x", b);
+        }
+        String result = formatter.toString();
+        formatter.close();
+        return result;
+    }
+
+    private static String create_nonce_str() {
+        return UUID.randomUUID().toString();
+    }
+
+    private static String create_timestamp() {
+        return Long.toString(System.currentTimeMillis() / 1000);
+    }
+}

+ 13 - 0
node/check_sign.js

@@ -0,0 +1,13 @@
+var sign = require('./sign.js');
+
+console.log(sign('jsapi_ticket', 'http://example.com'));
+/*
+ *something like this
+ *{
+ *  jsapi_ticket: 'jsapi_ticket',
+ *  nonceStr: '82zklqj7ycoywrk',
+ *  timestamp: '1415171822',
+ *  url: 'http://example.com',
+ *  signature: '1316ed92e0827786cfda3ae355f33760c4f70c1f'
+ *}
+ */

+ 6 - 0
node/node_modules/jssha/.npmignore

@@ -0,0 +1,6 @@
+build
+test
+src/sha_dev.js
+src/sha1.js
+src/sha256.js
+src/sha512.js

+ 99 - 0
node/node_modules/jssha/CHANGELOG

@@ -0,0 +1,99 @@
+-------------------------
+    jsSHA - ChangeLog
+-------------------------
+
+1.5 (2013-12-15)
+=========================
+- Added optional numRounds argument to getHash
+  - Note: this necessitated removing the hash result caching functionality
+- Reduced file size by optimizing internal constants
+- Removed charSize input and replaced with encoding to handle Unicode.  NOTE:
+  Only Code points up to 0xFFFF are supported.
+  - charSize = 16 is effectively replaced by encoding = "UTF16"
+  - charSize = 8 was wrong in terms of handling UTF-8 and has been replaced by
+    encoding = "UTF8"
+- Changed method of referencing "window" to be compatible with WebWorkers,
+  Node.js, and AMD (thanks piranna!)
+
+1.42 (2012-12-28)
+=========================
+- Readded v1.4 Safari patch to support older versions
+
+1.41 (2012-12-23)
+=========================
+- Fixed incorrect hash issue with Chrome x64 v25 (Dev channel), also provides
+  stable patch to v1.4 Safari issue.
+
+1.4 (2012-12-08)
+=========================
+- Added new input type, TEXT, that is functionally identical to ASCII*
+- Added new input type, B64, for base-64 encoded strings
+- Added new input and output formatting parameters
+  - getHash and getHMAC take an optional parameter, outputFormatOpts,
+    that is a hash list containing the keys "outputUpper" (boolean, only
+    applicable to HEX output) and "b64Pad" (string, only applicable to Base-64
+    output) that have default values of false and "=", respectively
+  - jsSHA constructor takes an optional parameter, charSize (8 or 16) that
+    specifies the character width of the input (TEXT and ASCII input only)
+- Modified comments to be Google Closure Compiler compliant
+- Added a SUPPORTED_ALGS flag that, when used with the Google Closure Compiler,
+  will remove unused functions/function portions
+  - Removed all src/*_nice.js files as the SUPPORTED_ALGS flag renders them
+    obsolete
+- All production-ready files are now produced using the Google Closure Compiler
+  with ADVANCED_OPTIMIZATIONS resulting in further reduced filesizes
+- The SHA-1 only implementation now requires that that "SHA-1" be specified as
+  the variant when using getHash and getHMAC
+- Removed test/HMAC.py as new NIST tests made the need for it obsolete
+- Significantly changed the test/test.html to make it easier to understand and
+  to allow for easier adding of test cases
+- Replaced previous error returning code with thrown exceptions
+- Fix for 64-bit Safari issue (thanks Ron Garret and Chris Warren-Smith!)
+  - NOTE: While this fix works, it is merely a workaround for a WebKit JavaScript
+   optimizer bug, see https://bugs.webkit.org/show_bug.cgi?id=88673 for more detail
+
+* This library misused the term ASCII so input type of TEXT was added with the
+  intention of deprecating ASCII
+
+1.31 (2012-07-21)
+=========================
+- Updated project URL to point to new GitHub repository
+- Added a compressed version of sha.js
+
+1.3 (2010-09-01)
+=========================
+- Changed method of declaring objects/classes
+- Moved non-instance specific variables and methods to class scope
+- Removed logically correct but unneeded conditionals
+
+1.2 (2009-07-22)
+=========================
+- Added the HMAC algorithm for all supported hashes (using both ASCII and hex
+  keys)
+- As a result of adding HMAC, added support for hash input text to be hex
+  (ASCII representation of hex)
+- Added multiple variants of safeAdd functions, resulting in a significant
+  performance gain
+- Removed wrapper.js file
+- Used a different JavaScript compressor resulting in smaller file sizes
+
+1.11 (2008-12-07)
+=========================
+- Fixed a base-64 encoding issue resulting from a missing capital 'X'
+
+1.1 (2008-09-25)
+=========================
+- Fixed an issue with incorrect hashes being generated when jsSHA ojbects were
+  used to generate multiple hashes
+
+1.0 (2008-09-25)
+=========================
+- Made all functions/variables follow an object-orientated methodology
+- Removed support for string hash output as the hash is rarely ASCII friendly
+- Changed the interface to calculate hashes (see README)
+- Made sha.js validate against JSLint (http://www.jslint.com/) using
+  "Recommended" settings
+
+0.1 (2008-02-21)
+=========================
+- Initial public release

+ 24 - 0
node/node_modules/jssha/LICENSE

@@ -0,0 +1,24 @@
+Copyright (c) 2008-2013, Brian Turek
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * The names of the contributors may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ANDANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIEDWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING,BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCEOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISEDOF THE POSSIBILITY OF SUCH DAMAGE.

+ 126 - 0
node/node_modules/jssha/README.md

@@ -0,0 +1,126 @@
+# jsSHA
+A JavaScript implementation of the complete Secure Hash Standard family
+		(SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512) as well as HMAC by
+		Brian Turek
+
+## About
+jsSHA is a javaScript implementation of the complete Secure Hash Algorithm
+family as defined by FIPS PUB 180-2
+(http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf).
+
+It also includes the HMAC algorithm with SHA support as defined by FIPS PUB 198-1
+(http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf)
+
+With the slow phasing out of MD5 as the standard hash to use in web
+applications, a client-side implementation of the complete Secure Hash Standard
+family was needed.  Due to SHA-384 and SHA-512's use of 64-bit values throughout
+the algorithm, JavaScript can not easily natively support the calculation of
+these hashes.  As a result, a bit of hacking had to be done to make sure the
+values behaved themselves. SHA-224 was added to the Secure Hash Standard family
+on 25 February 2004 so it was also included in this package.
+
+## Files
+**src/sha_dev.js**
+
+A commented implementation of the entire SHA family of hashes. Not to be used
+in production.
+
+**src/sha.js**
+
+A Google Closure Compiler optimized version of the entire library
+
+**src/sha1.js**
+
+A Google Closure Compiler optimized version the library with non SHA-1
+functionality removed
+
+**src/sha256.js**
+
+A Google Closure Compiler optimized version the library with non SHA-224/SHA-256
+functionality removed
+
+**src/sha512.js**
+
+A Google Closure Compiler optimized version the library with non SHA-384/SHA-512
+functionality removed
+
+**test/test.html**
+
+A test page that calculates various hashes and has their correct values
+
+**test/genHashRounds.py**
+
+A Python2 script that generates multi-round hash values
+
+**build/make-release**
+
+A Bash script that runs the various Google Closure Compiler commands to build
+a release
+
+**build/externs.js**
+
+File needed solely to make the Google Closure Compilter work
+
+## Usage
+
+### Browser
+Include the desired JavaScript file (sha.js, sha1.js, sha256.js, or sha512.js)
+in your header (sha.js used below):
+
+	<script type="text/javascript" src="/path/to/sha.js"></script>
+
+Instantiate a new jsSHA object with your string to be hashed and its format
+(HEX or TEXT) as the parameters.  Then, call getHash with the desired hash
+variant (SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512) and output type
+(HEX or B64).
+
+In the example below, "This is a Test" and "SHA-512" were used
+as the string to be hashed and variant respectively.  Also, the HMAC using TEXT
+key "SecretKey" and hashing algorithm SHA-512 was calculated.
+
+	var shaObj = new jsSHA("This is a Test", "TEXT");
+	var hash = shaObj.getHash("SHA-512", "HEX");
+	var hmac = shaObj.getHMAC("SecretKey", "TEXT", "SHA-512", "HEX");
+
+The constructor takes an optional parameter, encoding, that specifies the
+encoding used to encode TEXT-type inputs. Valid options are "UTF8" and "UTF16"
+and it defaults to "UTF8"
+
+getHash takes two optional parameters, a numRounds integer and an outputFormatOpts
+hashlist.  numRounds controls the number of hashing iterations/rounds performed
+and defaults to a value of "1" if not specified. outputFormatOpts dictates
+some formatting options for the output.  By default,
+`outputFormatOpts = {"outputUpper" : false, "b64Pad" : "="}`.  These
+options are intelligently interpreted based upon the chosen output format.
+
+getHMAC also takes an optional outputFormatOpts hashlist which operates the exact
+same way as above.
+
+### Node.js
+jsSHA is available through NPM and be installed by simply doing
+
+	npm install jssha
+To use the module, first require it using:
+
+	jsSHA = require("jssha");
+
+The rest of the instructions are identical to the [Browser](#browser) section above.
+
+## Compiling
+This library makes use of the Google Closure Compiler
+(https://developers.google.com/closure/compiler) to both boost performance
+and reduce filesizes.  To compile sha_dev.js into a customized output file, use
+a command like the following:
+
+	java -jar compiler.jar --define="SUPPORTED_ALGS=<FLAG>" \
+		--externs /path/to/build/externs.js --warning_level VERBOSE \
+		--compilation_level ADVANCED_OPTIMIZATIONS \
+		--js /path/to/sha_dev.js --js_output_file /path/to/sha.js
+		
+where <FLAG> is a bitwise OR of the following values:
+* 4 for SHA-384/SHA-512
+* 2 for SHA-224/256
+* 1 for SHA-1
+
+##Contact Info
+The project's website is located at [http://caligatio.github.com/jsSHA/](http://caligatio.github.com/jsSHA/)

+ 35 - 0
node/node_modules/jssha/bower.json

@@ -0,0 +1,35 @@
+{
+	"name" : "jsSHA",
+	"version" : "1.5.0",
+	"description" : "jsSHA is a JavaScript implementation of the entire family of SHA hashes as defined in FIPS 180-2 (SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512) as well as HMAC",
+	"main" : "src/sha.js",
+	"repository" : {
+		"type" : "git",
+		"url" : "https://github.com/Caligatio/jsSHA.git"
+	},
+	"keywords" : [
+		"SHA-1",
+		"SHA-256",
+		"SHA-224",
+		"SHA-384",
+		"SHA-512",
+		"SHA1",
+		"SHA256",
+		"SHA224",
+		"SHA384",
+		"SHA512",
+		"SHA2",
+		"HMAC",
+		"hash"
+	],
+	"license" : "BSD",
+	"authors" : [
+		"Brian Turek <brian.turek@gmail.com>"
+	],
+	"homepage" : "http://caligatio.github.com/jsSHA/",
+	"ignore": [
+		"build",
+		"test",
+		"src/sha_dev.js"
+	]
+}

File diff suppressed because it is too large
+ 41 - 0
node/node_modules/jssha/package.json


+ 34 - 0
node/node_modules/jssha/src/sha.js

@@ -0,0 +1,34 @@
+/*
+ A JavaScript implementation of the SHA family of hashes, as
+ defined in FIPS PUB 180-2 as well as the corresponding HMAC implementation
+ as defined in FIPS PUB 198a
+
+ Copyright Brian Turek 2008-2013
+ Distributed under the BSD License
+ See http://caligatio.github.com/jsSHA/ for more information
+
+ Several functions taken from Paul Johnston
+*/
+(function(T){function z(a,c,b){var g=0,f=[0],h="",l=null,h=b||"UTF8";if("UTF8"!==h&&"UTF16"!==h)throw"encoding must be UTF8 or UTF16";if("HEX"===c){if(0!==a.length%2)throw"srcString of HEX type must be in byte increments";l=B(a);g=l.binLen;f=l.value}else if("ASCII"===c||"TEXT"===c)l=J(a,h),g=l.binLen,f=l.value;else if("B64"===c)l=K(a),g=l.binLen,f=l.value;else throw"inputFormat must be HEX, TEXT, ASCII, or B64";this.getHash=function(a,c,b,h){var l=null,d=f.slice(),n=g,p;3===arguments.length?"number"!==
+typeof b&&(h=b,b=1):2===arguments.length&&(b=1);if(b!==parseInt(b,10)||1>b)throw"numRounds must a integer >= 1";switch(c){case "HEX":l=L;break;case "B64":l=M;break;default:throw"format must be HEX or B64";}if("SHA-1"===a)for(p=0;p<b;p++)d=y(d,n),n=160;else if("SHA-224"===a)for(p=0;p<b;p++)d=v(d,n,a),n=224;else if("SHA-256"===a)for(p=0;p<b;p++)d=v(d,n,a),n=256;else if("SHA-384"===a)for(p=0;p<b;p++)d=v(d,n,a),n=384;else if("SHA-512"===a)for(p=0;p<b;p++)d=v(d,n,a),n=512;else throw"Chosen SHA variant is not supported";
+return l(d,N(h))};this.getHMAC=function(a,b,c,l,s){var d,n,p,m,w=[],x=[];d=null;switch(l){case "HEX":l=L;break;case "B64":l=M;break;default:throw"outputFormat must be HEX or B64";}if("SHA-1"===c)n=64,m=160;else if("SHA-224"===c)n=64,m=224;else if("SHA-256"===c)n=64,m=256;else if("SHA-384"===c)n=128,m=384;else if("SHA-512"===c)n=128,m=512;else throw"Chosen SHA variant is not supported";if("HEX"===b)d=B(a),p=d.binLen,d=d.value;else if("ASCII"===b||"TEXT"===b)d=J(a,h),p=d.binLen,d=d.value;else if("B64"===
+b)d=K(a),p=d.binLen,d=d.value;else throw"inputFormat must be HEX, TEXT, ASCII, or B64";a=8*n;b=n/4-1;n<p/8?(d="SHA-1"===c?y(d,p):v(d,p,c),d[b]&=4294967040):n>p/8&&(d[b]&=4294967040);for(n=0;n<=b;n+=1)w[n]=d[n]^909522486,x[n]=d[n]^1549556828;c="SHA-1"===c?y(x.concat(y(w.concat(f),a+g)),a+m):v(x.concat(v(w.concat(f),a+g,c)),a+m,c);return l(c,N(s))}}function s(a,c){this.a=a;this.b=c}function J(a,c){var b=[],g,f=[],h=0,l;if("UTF8"===c)for(l=0;l<a.length;l+=1)for(g=a.charCodeAt(l),f=[],2048<g?(f[0]=224|
+(g&61440)>>>12,f[1]=128|(g&4032)>>>6,f[2]=128|g&63):128<g?(f[0]=192|(g&1984)>>>6,f[1]=128|g&63):f[0]=g,g=0;g<f.length;g+=1)b[h>>>2]|=f[g]<<24-h%4*8,h+=1;else if("UTF16"===c)for(l=0;l<a.length;l+=1)b[h>>>2]|=a.charCodeAt(l)<<16-h%4*8,h+=2;return{value:b,binLen:8*h}}function B(a){var c=[],b=a.length,g,f;if(0!==b%2)throw"String of HEX type must be in byte increments";for(g=0;g<b;g+=2){f=parseInt(a.substr(g,2),16);if(isNaN(f))throw"String of HEX type contains invalid characters";c[g>>>3]|=f<<24-g%8*4}return{value:c,
+binLen:4*b}}function K(a){var c=[],b=0,g,f,h,l,r;if(-1===a.search(/^[a-zA-Z0-9=+\/]+$/))throw"Invalid character in base-64 string";g=a.indexOf("=");a=a.replace(/\=/g,"");if(-1!==g&&g<a.length)throw"Invalid '=' found in base-64 string";for(f=0;f<a.length;f+=4){r=a.substr(f,4);for(h=l=0;h<r.length;h+=1)g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(r[h]),l|=g<<18-6*h;for(h=0;h<r.length-1;h+=1)c[b>>2]|=(l>>>16-8*h&255)<<24-b%4*8,b+=1}return{value:c,binLen:8*b}}function L(a,
+c){var b="",g=4*a.length,f,h;for(f=0;f<g;f+=1)h=a[f>>>2]>>>8*(3-f%4),b+="0123456789abcdef".charAt(h>>>4&15)+"0123456789abcdef".charAt(h&15);return c.outputUpper?b.toUpperCase():b}function M(a,c){var b="",g=4*a.length,f,h,l;for(f=0;f<g;f+=3)for(l=(a[f>>>2]>>>8*(3-f%4)&255)<<16|(a[f+1>>>2]>>>8*(3-(f+1)%4)&255)<<8|a[f+2>>>2]>>>8*(3-(f+2)%4)&255,h=0;4>h;h+=1)b=8*f+6*h<=32*a.length?b+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(l>>>6*(3-h)&63):b+c.b64Pad;return b}function N(a){var c=
+{outputUpper:!1,b64Pad:"="};try{a.hasOwnProperty("outputUpper")&&(c.outputUpper=a.outputUpper),a.hasOwnProperty("b64Pad")&&(c.b64Pad=a.b64Pad)}catch(b){}if("boolean"!==typeof c.outputUpper)throw"Invalid outputUpper formatting option";if("string"!==typeof c.b64Pad)throw"Invalid b64Pad formatting option";return c}function U(a,c){return a<<c|a>>>32-c}function u(a,c){return a>>>c|a<<32-c}function t(a,c){var b=null,b=new s(a.a,a.b);return b=32>=c?new s(b.a>>>c|b.b<<32-c&4294967295,b.b>>>c|b.a<<32-c&4294967295):
+new s(b.b>>>c-32|b.a<<64-c&4294967295,b.a>>>c-32|b.b<<64-c&4294967295)}function O(a,c){var b=null;return b=32>=c?new s(a.a>>>c,a.b>>>c|a.a<<32-c&4294967295):new s(0,a.a>>>c-32)}function V(a,c,b){return a^c^b}function P(a,c,b){return a&c^~a&b}function W(a,c,b){return new s(a.a&c.a^~a.a&b.a,a.b&c.b^~a.b&b.b)}function Q(a,c,b){return a&c^a&b^c&b}function X(a,c,b){return new s(a.a&c.a^a.a&b.a^c.a&b.a,a.b&c.b^a.b&b.b^c.b&b.b)}function Y(a){return u(a,2)^u(a,13)^u(a,22)}function Z(a){var c=t(a,28),b=t(a,
+34);a=t(a,39);return new s(c.a^b.a^a.a,c.b^b.b^a.b)}function $(a){return u(a,6)^u(a,11)^u(a,25)}function aa(a){var c=t(a,14),b=t(a,18);a=t(a,41);return new s(c.a^b.a^a.a,c.b^b.b^a.b)}function ba(a){return u(a,7)^u(a,18)^a>>>3}function ca(a){var c=t(a,1),b=t(a,8);a=O(a,7);return new s(c.a^b.a^a.a,c.b^b.b^a.b)}function da(a){return u(a,17)^u(a,19)^a>>>10}function ea(a){var c=t(a,19),b=t(a,61);a=O(a,6);return new s(c.a^b.a^a.a,c.b^b.b^a.b)}function R(a,c){var b=(a&65535)+(c&65535);return((a>>>16)+(c>>>
+16)+(b>>>16)&65535)<<16|b&65535}function fa(a,c,b,g){var f=(a&65535)+(c&65535)+(b&65535)+(g&65535);return((a>>>16)+(c>>>16)+(b>>>16)+(g>>>16)+(f>>>16)&65535)<<16|f&65535}function S(a,c,b,g,f){var h=(a&65535)+(c&65535)+(b&65535)+(g&65535)+(f&65535);return((a>>>16)+(c>>>16)+(b>>>16)+(g>>>16)+(f>>>16)+(h>>>16)&65535)<<16|h&65535}function ga(a,c){var b,g,f;b=(a.b&65535)+(c.b&65535);g=(a.b>>>16)+(c.b>>>16)+(b>>>16);f=(g&65535)<<16|b&65535;b=(a.a&65535)+(c.a&65535)+(g>>>16);g=(a.a>>>16)+(c.a>>>16)+(b>>>
+16);return new s((g&65535)<<16|b&65535,f)}function ha(a,c,b,g){var f,h,l;f=(a.b&65535)+(c.b&65535)+(b.b&65535)+(g.b&65535);h=(a.b>>>16)+(c.b>>>16)+(b.b>>>16)+(g.b>>>16)+(f>>>16);l=(h&65535)<<16|f&65535;f=(a.a&65535)+(c.a&65535)+(b.a&65535)+(g.a&65535)+(h>>>16);h=(a.a>>>16)+(c.a>>>16)+(b.a>>>16)+(g.a>>>16)+(f>>>16);return new s((h&65535)<<16|f&65535,l)}function ia(a,c,b,g,f){var h,l,r;h=(a.b&65535)+(c.b&65535)+(b.b&65535)+(g.b&65535)+(f.b&65535);l=(a.b>>>16)+(c.b>>>16)+(b.b>>>16)+(g.b>>>16)+(f.b>>>
+16)+(h>>>16);r=(l&65535)<<16|h&65535;h=(a.a&65535)+(c.a&65535)+(b.a&65535)+(g.a&65535)+(f.a&65535)+(l>>>16);l=(a.a>>>16)+(c.a>>>16)+(b.a>>>16)+(g.a>>>16)+(f.a>>>16)+(h>>>16);return new s((l&65535)<<16|h&65535,r)}function y(a,c){var b=[],g,f,h,l,r,s,u=P,t=V,v=Q,d=U,n=R,p,m,w=S,x,q=[1732584193,4023233417,2562383102,271733878,3285377520];a[c>>>5]|=128<<24-c%32;a[(c+65>>>9<<4)+15]=c;x=a.length;for(p=0;p<x;p+=16){g=q[0];f=q[1];h=q[2];l=q[3];r=q[4];for(m=0;80>m;m+=1)b[m]=16>m?a[m+p]:d(b[m-3]^b[m-8]^b[m-
+14]^b[m-16],1),s=20>m?w(d(g,5),u(f,h,l),r,1518500249,b[m]):40>m?w(d(g,5),t(f,h,l),r,1859775393,b[m]):60>m?w(d(g,5),v(f,h,l),r,2400959708,b[m]):w(d(g,5),t(f,h,l),r,3395469782,b[m]),r=l,l=h,h=d(f,30),f=g,g=s;q[0]=n(g,q[0]);q[1]=n(f,q[1]);q[2]=n(h,q[2]);q[3]=n(l,q[3]);q[4]=n(r,q[4])}return q}function v(a,c,b){var g,f,h,l,r,t,u,v,z,d,n,p,m,w,x,q,y,C,D,E,F,G,H,I,e,A=[],B,k=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,
+1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,
+2361852424,2428436474,2756734187,3204031479,3329325298];d=[3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428];f=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225];if("SHA-224"===b||"SHA-256"===b)n=64,g=(c+65>>>9<<4)+15,w=16,x=1,e=Number,q=R,y=fa,C=S,D=ba,E=da,F=Y,G=$,I=Q,H=P,d="SHA-224"===b?d:f;else if("SHA-384"===b||"SHA-512"===b)n=80,g=(c+128>>>10<<5)+31,w=32,x=2,e=s,q=ga,y=ha,C=ia,D=ca,E=ea,F=Z,G=aa,I=X,H=W,k=[new e(k[0],
+3609767458),new e(k[1],602891725),new e(k[2],3964484399),new e(k[3],2173295548),new e(k[4],4081628472),new e(k[5],3053834265),new e(k[6],2937671579),new e(k[7],3664609560),new e(k[8],2734883394),new e(k[9],1164996542),new e(k[10],1323610764),new e(k[11],3590304994),new e(k[12],4068182383),new e(k[13],991336113),new e(k[14],633803317),new e(k[15],3479774868),new e(k[16],2666613458),new e(k[17],944711139),new e(k[18],2341262773),new e(k[19],2007800933),new e(k[20],1495990901),new e(k[21],1856431235),
+new e(k[22],3175218132),new e(k[23],2198950837),new e(k[24],3999719339),new e(k[25],766784016),new e(k[26],2566594879),new e(k[27],3203337956),new e(k[28],1034457026),new e(k[29],2466948901),new e(k[30],3758326383),new e(k[31],168717936),new e(k[32],1188179964),new e(k[33],1546045734),new e(k[34],1522805485),new e(k[35],2643833823),new e(k[36],2343527390),new e(k[37],1014477480),new e(k[38],1206759142),new e(k[39],344077627),new e(k[40],1290863460),new e(k[41],3158454273),new e(k[42],3505952657),
+new e(k[43],106217008),new e(k[44],3606008344),new e(k[45],1432725776),new e(k[46],1467031594),new e(k[47],851169720),new e(k[48],3100823752),new e(k[49],1363258195),new e(k[50],3750685593),new e(k[51],3785050280),new e(k[52],3318307427),new e(k[53],3812723403),new e(k[54],2003034995),new e(k[55],3602036899),new e(k[56],1575990012),new e(k[57],1125592928),new e(k[58],2716904306),new e(k[59],442776044),new e(k[60],593698344),new e(k[61],3733110249),new e(k[62],2999351573),new e(k[63],3815920427),new e(3391569614,
+3928383900),new e(3515267271,566280711),new e(3940187606,3454069534),new e(4118630271,4000239992),new e(116418474,1914138554),new e(174292421,2731055270),new e(289380356,3203993006),new e(460393269,320620315),new e(685471733,587496836),new e(852142971,1086792851),new e(1017036298,365543100),new e(1126000580,2618297676),new e(1288033470,3409855158),new e(1501505948,4234509866),new e(1607167915,987167468),new e(1816402316,1246189591)],d="SHA-384"===b?[new e(3418070365,d[0]),new e(1654270250,d[1]),new e(2438529370,
+d[2]),new e(355462360,d[3]),new e(1731405415,d[4]),new e(41048885895,d[5]),new e(3675008525,d[6]),new e(1203062813,d[7])]:[new e(f[0],4089235720),new e(f[1],2227873595),new e(f[2],4271175723),new e(f[3],1595750129),new e(f[4],2917565137),new e(f[5],725511199),new e(f[6],4215389547),new e(f[7],327033209)];else throw"Unexpected error in SHA-2 implementation";a[c>>>5]|=128<<24-c%32;a[g]=c;B=a.length;for(p=0;p<B;p+=w){c=d[0];g=d[1];f=d[2];h=d[3];l=d[4];r=d[5];t=d[6];u=d[7];for(m=0;m<n;m+=1)A[m]=16>m?
+new e(a[m*x+p],a[m*x+p+1]):y(E(A[m-2]),A[m-7],D(A[m-15]),A[m-16]),v=C(u,G(l),H(l,r,t),k[m],A[m]),z=q(F(c),I(c,g,f)),u=t,t=r,r=l,l=q(h,v),h=f,f=g,g=c,c=q(v,z);d[0]=q(c,d[0]);d[1]=q(g,d[1]);d[2]=q(f,d[2]);d[3]=q(h,d[3]);d[4]=q(l,d[4]);d[5]=q(r,d[5]);d[6]=q(t,d[6]);d[7]=q(u,d[7])}if("SHA-224"===b)a=[d[0],d[1],d[2],d[3],d[4],d[5],d[6]];else if("SHA-256"===b)a=d;else if("SHA-384"===b)a=[d[0].a,d[0].b,d[1].a,d[1].b,d[2].a,d[2].b,d[3].a,d[3].b,d[4].a,d[4].b,d[5].a,d[5].b];else if("SHA-512"===b)a=[d[0].a,
+d[0].b,d[1].a,d[1].b,d[2].a,d[2].b,d[3].a,d[3].b,d[4].a,d[4].b,d[5].a,d[5].b,d[6].a,d[6].b,d[7].a,d[7].b];else throw"Unexpected error in SHA-2 implementation";return a}"function"===typeof define&&typeof define.amd?define(function(){return z}):"undefined"!==typeof exports?"undefined"!==typeof module&&module.exports?module.exports=exports=z:exports=z:T.jsSHA=z})(this);

+ 15 - 0
node/package.json

@@ -0,0 +1,15 @@
+{
+  "name": "wechat_jsapi_sign",
+  "version": "1.0.0",
+  "description": "",
+  "main": "sign.js",
+  "dependencies": {
+    "jssha": "^1.5.0"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC"
+}

+ 48 - 0
node/sign.js

@@ -0,0 +1,48 @@
+var createNonceStr = function () {
+  return Math.random().toString(36).substr(2, 15);
+};
+
+var createTimestamp = function () {
+  return parseInt(new Date().getTime() / 1000) + '';
+};
+
+var raw = function (args) {
+  var keys = Object.keys(args);
+  keys = keys.sort()
+  var newArgs = {};
+  keys.forEach(function (key) {
+    newArgs[key.toLowerCase()] = args[key];
+  });
+
+  var string = '';
+  for (var k in newArgs) {
+    string += '&' + k + '=' + newArgs[k];
+  }
+  string = string.substr(1);
+  return string;
+};
+
+/**
+* @synopsis 签名算法 
+*
+* @param jsapi_ticket 用于签名的 jsapi_ticket
+* @param url 用于签名的 url ,注意必须动态获取,不能 hardcode
+*
+* @returns
+*/
+var sign = function (jsapi_ticket, url) {
+  var ret = {
+    jsapi_ticket: jsapi_ticket,
+    nonceStr: createNonceStr(),
+    timestamp: createTimestamp(),
+    url: url
+  };
+  var string = raw(ret);
+      jsSHA = require('jssha');
+      shaObj = new jsSHA(string, 'TEXT');
+  ret.signature = shaObj.getHash('SHA-1', 'HEX');
+
+  return ret;
+};
+
+module.exports = sign;

+ 2 - 0
php/access_token.php

@@ -0,0 +1,2 @@
+<?php exit();?>
+{"access_token":"","expire_time":0}

+ 2 - 0
php/jsapi_ticket.php

@@ -0,0 +1,2 @@
+<?php exit();?>
+{"jsapi_ticket":"","expire_time":0}

+ 113 - 0
php/jssdk.php

@@ -0,0 +1,113 @@
+<?php
+class JSSDK {
+  private $appId;
+  private $appSecret;
+
+  public function __construct($appId, $appSecret) {
+    $this->appId = $appId;
+    $this->appSecret = $appSecret;
+  }
+
+  public function getSignPackage() {
+    $jsapiTicket = $this->getJsApiTicket();
+
+    // 注意 URL 一定要动态获取,不能 hardcode.
+    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
+    $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
+
+    $timestamp = time();
+    $nonceStr = $this->createNonceStr();
+
+    // 这里参数的顺序要按照 key 值 ASCII 码升序排序
+    $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
+
+    $signature = sha1($string);
+
+    $signPackage = array(
+      "appId"     => $this->appId,
+      "nonceStr"  => $nonceStr,
+      "timestamp" => $timestamp,
+      "url"       => $url,
+      "signature" => $signature,
+      "rawString" => $string
+    );
+    return $signPackage; 
+  }
+
+  private function createNonceStr($length = 16) {
+    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    $str = "";
+    for ($i = 0; $i < $length; $i++) {
+      $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
+    }
+    return $str;
+  }
+
+  private function getJsApiTicket() {
+    // jsapi_ticket 应该全局存储与更新,以下代码以写入到文件中做示例
+    $data = json_decode($this->get_php_file("jsapi_ticket.php"));
+    if ($data->expire_time < time()) {
+      $accessToken = $this->getAccessToken();
+      // 如果是企业号用以下 URL 获取 ticket
+      // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
+      $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
+      $res = json_decode($this->httpGet($url));
+      $ticket = $res->ticket;
+      if ($ticket) {
+        $data->expire_time = time() + 7000;
+        $data->jsapi_ticket = $ticket;
+        $this->set_php_file("jsapi_ticket.php", json_encode($data));
+      }
+    } else {
+      $ticket = $data->jsapi_ticket;
+    }
+
+    return $ticket;
+  }
+
+  private function getAccessToken() {
+    // access_token 应该全局存储与更新,以下代码以写入到文件中做示例
+    $data = json_decode($this->get_php_file("access_token.php"));
+    if ($data->expire_time < time()) {
+      // 如果是企业号用以下URL获取access_token
+      // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
+      $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
+      $res = json_decode($this->httpGet($url));
+      $access_token = $res->access_token;
+      if ($access_token) {
+        $data->expire_time = time() + 7000;
+        $data->access_token = $access_token;
+        $this->set_php_file("access_token.php", json_encode($data));
+      }
+    } else {
+      $access_token = $data->access_token;
+    }
+    return $access_token;
+  }
+
+  private function httpGet($url) {
+    $curl = curl_init();
+    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($curl, CURLOPT_TIMEOUT, 500);
+    // 为保证第三方服务器与微信服务器之间数据传输的安全性,所有微信接口采用https方式调用,必须使用下面2行代码打开ssl安全校验。
+    // 如果在部署过程中代码在此处验证失败,请到 http://curl.haxx.se/ca/cacert.pem 下载新的证书判别文件。
+    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
+    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, true);
+    curl_setopt($curl, CURLOPT_URL, $url);
+
+    $res = curl_exec($curl);
+    curl_close($curl);
+
+    return $res;
+  }
+
+  private function get_php_file($filename) {
+    return trim(substr(file_get_contents($filename), 15));
+  }
+  private function set_php_file($filename, $content) {
+    $fp = fopen($filename, "w");
+    fwrite($fp, "<?php exit();?>" . $content);
+    fclose($fp);
+  }
+}
+

+ 42 - 0
php/sample.php

@@ -0,0 +1,42 @@
+<?php
+require_once "jssdk.php";
+$jssdk = new JSSDK("yourAppID", "yourAppSecret");
+$signPackage = $jssdk->GetSignPackage();
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title></title>
+</head>
+<body>
+  
+</body>
+<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
+<script>
+  /*
+   * 注意:
+   * 1. 所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
+   * 2. 如果发现在 Android 不能分享自定义内容,请到官网下载最新的包覆盖安装,Android 自定义分享接口需升级至 6.0.2.58 版本及以上。
+   * 3. 常见问题及完整 JS-SDK 文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
+   *
+   * 开发中遇到问题详见文档“附录5-常见错误及解决办法”解决,如仍未能解决可通过以下渠道反馈:
+   * 邮箱地址:weixin-open@qq.com
+   * 邮件主题:【微信JS-SDK反馈】具体问题
+   * 邮件内容说明:用简明的语言描述问题所在,并交代清楚遇到该问题的场景,可附上截屏图片,微信团队会尽快处理你的反馈。
+   */
+  wx.config({
+    debug: true,
+    appId: '<?php echo $signPackage["appId"];?>',
+    timestamp: <?php echo $signPackage["timestamp"];?>,
+    nonceStr: '<?php echo $signPackage["nonceStr"];?>',
+    signature: '<?php echo $signPackage["signature"];?>',
+    jsApiList: [
+      // 所有要调用的 API 都要加到这个列表中
+    ]
+  });
+  wx.ready(function () {
+    // 在这里调用 API
+  });
+</script>
+</html>

+ 30 - 0
python/sign.py

@@ -0,0 +1,30 @@
+import time
+import random
+import string
+import hashlib
+
+class Sign:
+    def __init__(self, jsapi_ticket, url):
+        self.ret = {
+            'nonceStr': self.__create_nonce_str(),
+            'jsapi_ticket': jsapi_ticket,
+            'timestamp': self.__create_timestamp(),
+            'url': url
+        }
+
+    def __create_nonce_str(self):
+        return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(15))
+
+    def __create_timestamp(self):
+        return int(time.time())
+
+    def sign(self):
+        string = '&'.join(['%s=%s' % (key.lower(), self.ret[key]) for key in sorted(self.ret)])
+        print string
+        self.ret['signature'] = hashlib.sha1(string).hexdigest()
+        return self.ret
+
+if __name__ == '__main__':
+    # 注意 URL 一定要动态获取,不能 hardcode
+    sign = Sign('jsapi_ticket', 'http://example.com')
+    print sign.sign()

Some files were not shown because too many files changed in this diff