Unable to produce Proper Encryption Key in Ruby using HMAC - ruby

I am attempting to follow the documentation per Access Control and interrogating code like azure-documentdb-node SDK and I am unable to do so.
I get the following error: 401 Unauthorized: {"code":"Unauthorized","message":"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndbs\n\n13 april 2015 18:21:05 gmt\n\n'\r\nActivityId: ...
My ruby code looks like the following:
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
Thanks!
EDIT: After Ryan's advice and example I've simplified the code down to the following snippit that should be a match for the node code he has posted BUT it still fails in ruby:
def hard_coded_get_databases master_key, url
verb = "get"
resource_type = "dbs"
resource_id = ""
date = Time.now.httpdate
serv_version = '2014-08-21'
master_token = "master"
token_version = "1.0"
key = Base64.decode64 master_key
text = verb + "\n" + resource_type + "\n" + resource_id + "\n" + date + "\n\n"
body = text.downcase.force_encoding "utf-8"
signature = OpenSSL::HMAC.digest OpenSSL::Digest::SHA256.new, key, body
auth_token = URI.escape("type="+master_token + "&ver="+token_version + "&sig="+signature)
header = { "accept" => "application/json", "x-ms-version" => serv_version, "x-ms-date" => date, "authorization" => auth_token }
RestClient.get url, header
end
EDIT2: I believe I've isolated the problem to how I am doing the master key authentication.
Taking Ryan's example we can trim his node code down the following:
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
If I call this node code I can produce the following key:
encode_message("blah", 'get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n')
'IYlLuyZtVLx5ANkGMAxviDHgC/DJJXSj1gUGLvN0oM8='
If I produce the equivalent ruby code to create the authentication my ruby code looks like the following:
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
If I call this code I get the following:
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
Clearly the 2 encoded auth tokens are not the same. (Ryan again thanks so much for the help to get this far).

I have found the answer. Thanks to Magnus Stahre ... he is the man for helping me figure it out.
It was the encoding as I thought and the trick is this:
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message.downcase
Base64.encode64(hmac).strip
end
I was downcasing in my code too early AND my Base64.encode64 was failing to strip away a newline character that ruby was adding on the end.

i'll start off by apologizing for my limited Ruby knowledge but let me try assist here;
in your get_master_auth_token function it appears you are decoding the key before using it. is this correct? if so, why?
here is a node.js sample that uses the master key, builds up the auth header value and does a simple http call to list the collections in a database
var crypto = require("crypto");
var https = require("https");
https.globalAgent.options.secureProtocol = "TLSv1_client_method";
var verb = 'get';
var resourceType = 'dbs'; //the resource you are trying to get. dbs, colls, docs etc.
var resourceId = ''; //the parent resource id. note: not the id, but the _rid. but for you, because you are trying to lookup list of databases there is no parent
var masterKey = '...'; //your masterkey
var date = new Date().toUTCString();
var auth = getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey);
var options = {
hostname: '...', //your hostname (without https://)
port: 443,
path: '/dbs/',
method: 'GET',
headers: {
accept: 'application/json',
'x-ms-version': '2014-08-21',
'x-ms-date': date,
authorization: auth,
}
};
for (var i = 0; i < 1000; i++) {
var req = https.request(options, function (res) {
process.stdout.write(new Date().toUTCString() + " - statusCode: " + res.statusCode + "\n");
res.on('data', function (d) {
}).on('error', function (e) {
})
});
//console.log(req);
req.end();
}
function getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey) {
var key = new Buffer(masterKey, "base64");
var text = (verb || "") + "\n" +
(resourceType || "") + "\n" +
(resourceId || "") + "\n" +
(date || "") + "\n" +
("") + "\n";
var body = new Buffer(text.toLowerCase(), "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);
}
In your example, the resourceId passed to the getAuthorizationTokenUsingMasterKey method should be "" and the resourceType should be "dbs" as you have it.
I did notice that in some cases you have to URI Encode the value, but I think you are doing that already as the very last line of the func.
the only difference I can spot in your code vs my code is that you appear to be decoding the master_key which I don't do.
what I would recommend you do is run this node sample and compare the values of the strings we have in body & signature to the your values. they need to match.

Related

Generating RSA JWT in Postman Pre-request script

I have the following pre-request script that i am using to attempt to generate a JWT for Google Api - Google uses the RS256 encryption which is where I think I am getting stuck - the CryptoJS seems to support HmacSHA256 only - Any advise would be helpful:
Here's my pre-request script from Postman:
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) - 100;
data.iat = iat;
return data;
}
function addEXP(request) {
var exp = Math.floor(Date.now() / 1000) + 3300;
data.exp = exp;
return data;
}
var header = {
"alg": "RS256",
"typ": "JWT",
"kid": "xxx"
};
var data = {
"iss": "xxx#iam.gserviceaccount.com",
"aud": "https://oauth2.googleapis.com/token",
"scope": "https://www.googleapis.com/auth/cloud-platform"
};
data = addIAT(data);
data = addEXP(data);
var privateKEY = "-----BEGIN PRIVATE KEY-----xxxxxxxxxxxxxxxLcGGNkna2Y3URoT0vDNneqzaasmJk4JZ97BcFLOulTihA49z8zmQKBgQDKX9AWS88cnfyiXSxtRNUFYvN4SzMDTJ1o59Gm6Sk77t7Ylfm+8PKA00SQeN7FuU/cbU4PkbAyzcp7eAGE3KXoLC/pWQ14srWGAsQkti1PmBo400ajRQReJPs3XxIl3yl4swlRgn+w9x6xy3CRnWrZRQSxRrtdDkBJcp7Lml+4mwKBgQCCeiTsktlMTOy9LqxOUMh6Lt7Z5jceNSwusW8Z4YVsewiSsRezufLBRcTywifgPOyUTP3S7etEfW2CKF0smpM0drfxd/3Ic7oKr7ESY5zwNcV7Q3NUGxaqGy8yoxEhKkLsYkOzYUdyNyfJd5Sh8yq7ICrX7/UGkVLOi44VrdaluQKBgC3kmH3V5zvoH/h6BK8q4tv72pa3BvSClVfK6mJdkbpDq0mWiTJh1bydLHlOz8YrBg9IwmEJetmqjXZ+emm01/LUwnC6fzGV5VBkpDJnFdNs/NVSJDy2VA09ebLO3oC0IOV8RGq1m1t4Tv+m0PpUpnxrCGtjTO4HY1DEq3okofxtAoGABjq4QegVIlImU5LSAEKgnUiwA1CHGW3+ZzfCczAv2VRfk/DSlYLmsxLRIfjsCVEo79NiVGyIsKmt5TJRxVLXp++ydKCEN/YRrjqEFgHNoH0rDCuV/IKAeN17/TYKphuebSX6mVsfo7GXI1kSoGJkDDnPKR4peiIF/YC9BTqQgIs=-----END PRIVATE KEY-----"
var secret = 'myjwtsecret';
// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
//encode privatekey
//var stringifiedPrivatekey = CryptoJS.enc.Utf8.parse(JSON.stringify(privateKEY));
//var encodedPrivatekey = base64url(stringifiedPrivatekey);
// build token
var token = encodedHeader + "." + encodedData
// sign token
//var signature = CryptoJS.HmacSHA256(token, secret);
//signature = base64url(signature);
var signature = CryptoJS.RS256(token , privateKEY);
signedToken = base64url(signature);
var jwt = token + "." + signedToken
postman.setEnvironmentVariable("payload", jwt);
I have found this problem a couple of time in my projects so I decide to create an easy way to do this, here https://joolfe.github.io/postman-util-lib/ i have publish a ¨library¨ to easy do cryptographic operations like generate jwt, PKCE challenges... in ¨Pre-request¨ and ¨Tests¨ scripts in postman, have a look and contact me if you have any doubts.
Best Regards.

How to upload a catalog file to azure cognitive service with ruby?

I want upload a catalog file to recommendation api (Azure Cognitive Service with ruby language.
With C# I will have the next code (extracted from https://github.com/Microsoft/Cognitive-Recommendations-Windows/blob/master/Sample/RecommendationsApiWrapper.cs):
public CatalogImportStats UploadCatalog(string modelId, string catalogFilePath, string catalogDisplayName)
{
Console.WriteLine("Uploading " + catalogDisplayName + " ...");
string uri = BaseUri + "/models/" + modelId + "/catalog?catalogDisplayName=" + catalogDisplayName;
using (var filestream = new FileStream(catalogFilePath, FileMode.Open, FileAccess.Read))
{
var response = _httpClient.PostAsync(uri, new StreamContent(filestream)).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception(
String.Format("Error {0}: Failed to import catalog items {1}, for model {2} \n reason {3}",
response.StatusCode, catalogFilePath, modelId, ExtractErrorInfo(response)));
}
var jsonString = ExtractReponse(response);
var catalogImportStats = JsonConvert.DeserializeObject<CatalogImportStats>(jsonString);
return catalogImportStats;
}
How to upload a catalog file to cognitive service using ruby and http client?. I need a basic sample code.
Thanks
I've uploaded a sample here: https://github.com/miparnisari/ruby-cognitive-services
But the gist of it:
require 'net/http'
require 'IO/console'
class RecommendationsClient
def initialize(subscription_key, region)
#base_url="https://#{region}.api.cognitive.microsoft.com/recommendations/v4.0"
#subscription_key=subscription_key
end
def upload_catalog(model_id, catalog_display_name, catalog_path)
uri = URI("#{#base_url}/models/#{model_id}/catalog?catalogDisplayName=#{catalog_display_name}")
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/octet-stream'
request['Ocp-Apim-Subscription-Key'] = "#{#subscription_key}"
request.body = IO.binread(catalog_path)
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
return response.body
end
end
And then:
r = RecommendationsClient.new("your_key_here", "westus")
response = r.upload_catalog('1', 'catalog', 'books_catalog.txt')
puts response

Host.updateLicenseRequestInfo not able to add headers

Hi I am trying to achieve any one of the below
1) Set a extra token to the license url by the code ' requestInfo.url = requestInfo.url + "#12345678";'
OR
2) Set headers by the code 'requestInfo.headers = new String('token:12345678\r\n');'
But nothing seems to work.
After updating the url in receiver logs i see 'Updated requestInfo.url ' with the extra '#12345678' at the end of the license url. But on license server I get only the url which is unmodified ( no #12345678).
Same with requestInfo.headers. I don't see any headers which I set in receiver app when the request comes in license server.
I also tried returning the requestInfo; but with this the chromecast is not able to play anything. So I commented the return statement.
Would appreciate any pointers to fix this issue. Here is my code.
var host = new cast.player.api.Host({
'url': url,
'mediaElement': this.mediaElement_
});
host.onManifestReady = function() {
self.log_('prototype.loadVideo_::My onManifestReady');
};
host.updateLicenseRequestInfo = function(requestInfo){
self.log_('prototype.loadVideo_::updateLicenseRequestInfo()');
self.log_('requestInfo.url ' + requestInfo.url);
self.log_('requestInfo.headers ' + requestInfo.headers);
self.log_('requestInfo.protectionSystem ' + requestInfo.protectionSystem);
self.log_('requestInfo.setResponse ' + requestInfo.setResponse);
self.log_('requestInfo.skipRequest ' + requestInfo.skipRequest);
self.log_('requestInfo.timeoutInterval ' + requestInfo.timeoutInterval);
self.log_('requestInfo.withCredentials ' + requestInfo.withCredentials );
requestInfo.url = requestInfo.url + "#12345678";
//host.licenseUrl = requestInfo.url;
//requestInfo.headers = new String('token:12345678\r\n');
self.log_('Updated requestInfo.url ' + requestInfo.url);
self.log_('Updated requestInfo.headers ' + requestInfo.headers);
//return requestInfo;
};
this.player_ = new cast.player.api.Player(host);
updateLicenseRequestInfo - enables the host to customize request information used to get media license from the server. Applications should override this method to add a token to the url, set headers or withCredentials flag.
Here is the example code on how to use it.
host.updateManifestRequestInfo = function(requestInfo) {
if (!requestInfo.url) {
requestInfo.url = this.url;
}
requestInfo.withCredentials = true;
};
host.updateLicenseRequestInfo = function(requestInfo) {
requestInfo.withCredentials = true;
};
host.updateSegmentRequestInfo = function(requestInfo) {
requestInfo.withCredentials = true;
};
You can also visit this page for more information.

Need assistance with creating a Git client-side 'commit-msg' hook

I have installed the 'ticket_status.rb' server-side hook on Assembla. Although this is exactly what I'm looking for (in theory), it does not flag until the developer attempts to push to the server. If they have made several commits before pushing, it becomes incredibly frustrating to go back through their history and edit any invalid commit messages.
I am looking to create a client-side hook that will reject a developer's commit if an open ticket in Assembla is not referenced in the commit message. I assume that since it is client-side, it will not be able to check if the ticket is open in the Assembla project space. However, if the hook could at least check that '#n' has been included in the commit message (where 0 < n < 10,000), it should catch the majority of invalid commit messages.
GitHub has provided sample code for a client-side 'commit-msg' hook. I would like assistance in modifying the code below to instead search for a ticket number (#n) in the commit message (or an open ticket in the Assembla project space, if possible):
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}
I have also provided the source code for the server-side hook that rejects the commit if it does not contain a valid open ticket number in the commit message (ticket_status.rb):
#!/usr/bin/env ruby
# -*- encoding : utf-8 -*-
#
# Reject a push to a branch if it has commits that do refer a ticket in open state
#
# ref = ARGV[0]
sha_start = ARGV[1]
sha_end = ARGV[2]
# HOOK PARAMS
space = 'space-wiki-name'
api_key = 'user-api-key'
api_secret = 'user-api-secret'
# HOOK START, end of params block
require "net/https"
require "uri"
begin
require "json"
rescue LoadError
require 'rubygems'
require 'json'
end
# Check referred tickets that are in open stage
class TicketValidator
API_URL = "https://api.assembla.com"
attr_accessor :space, :api_key, :api_secret
def initialize()
#ticket_statuses = []
#tickets = {}
end
def init
init_http
load_statuses
end
def check(sha, comment)
comment.to_s.scan(/#\d+/).each do |t|
ticket = t.tr('#', '')
# Do not check it twice
next if #tickets[ticket]
ticket_js = api_call "/v1/spaces/#{space}/tickets/#{ticket}.json"
error = nil
if ticket_js['error'].nil?
unless #ticket_statuses.include? ticket_js['status'].downcase
error = "Ticket #{t} is not open!"
end
else
error = ticket_js['error']
end
if error
#tickets[ticket] = {:error => error, :sha => sha}
else
#tickets[ticket] = :ok
end
end
end
def load_statuses
statuses = api_call "/v1/spaces/#{space}/tickets/statuses.json"
statuses.each do |status|
if status["state"] == 1 # open
#ticket_statuses << status["name"].downcase
end
end
end
def api_call(uri)
request = Net::HTTP::Get.new(uri,
{'Content-Type' => 'application/json',
'X-Api-Key' => api_key,
'X-Api-Secret' => api_secret})
result = #http.request(request)
JSON.parse(result.body)
end
def init_http
uri = URI.parse(API_URL)
#http = Net::HTTP.new(uri.host, uri.port)
#http.use_ssl = true
#http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
def show_decision!
#tickets.reject! {|_, value| value == :ok }
unless #tickets.empty?
puts "You have references to tickets in closed state"
#tickets.each do |ticket, details|
puts "\t#{details[:sha]} - ##{ticket} #{details[:error]}"
end
puts "Valid statuses: #{#ticket_statuses.join(', ')}"
exit 1
end
end
end
class Parser
def initialize(text, validator)
#text = text
#validator = validator
end
def parse
commit = nil
comment = nil
#validator.init
#text.to_s.split("\n").each do |line|
if line =~ /^commit: ([a-z0-9]+)$/i
new_commit = $1
if comment
#validator.check(commit, comment)
comment = nil
end
commit = new_commit
else
comment = comment.to_s + line + "\n"
end
end
# Check last commit
#validator.check(commit, comment) if comment
end
end
text = `git log --pretty='format:commit: %h%n%B' #{sha_start}..#{sha_end}`
#validator = TicketValidator.new
#validator.space = space
#validator.api_key = api_key
#validator.api_secret = api_secret
Parser.new(text, #validator).parse
#validator.show_decision!
Any help is much appreciated. Thanks
You can try this commit-msg validator. It's not ruby but you can easily configure it for your needs and you can even write your own Assembla reference to validate ticket numbers against their API. See the repo README for more details.
Here is a starting point for your custom reference, and its associated test file. I haven't tested it thoroughly but it should be pretty easy to change as you wish, since it's basically JavaScript.
lib/references/assembla.js
'use strict';
var exec = require('child_process').exec;
var https = require('https');
var util = require('util');
// HOOK PARAMS
var space = 'space-wiki-name';
var apiKey = 'user-api-key';
var apiSecret = 'user-api-secret';
function Ticket(ticket, match) {
this.allowInSubject = true;
this.match = match;
this._ticket = ticket;
}
Ticket.prototype.toString = function() {
return '#' + this._ticket;
}
Ticket.prototype.isValid = function(cb) {
var options = {
hostname: 'api.assembla.com',
path: util.format('/v1/spaces/%s/tickets/%s.json', space, this._ticket),
headers: {
'Content-Type' : 'application/json',
'X-Api-Key' : apiKey,
'X-Api-Secret' : apiSecret
}
};
https.get(options, function(res) {
if (res.statusCode === 404) {
return cb(null, false); // invalid
}
var body = '';
res.on('data', function(chunk) {
body += chunk.toString();
});
res.on('end', function () {
var response = body ? JSON.parse(body) : false;
if (res.statusCode < 300 && response) {
return cb(null, true); // valid?
}
console.error('warning: Reference check failed with status code %d',
res.statusCode,
response && response.message ? ('; reason: ' + response.message) : '');
cb(null, false); // request errored out?
});
});
}
// Fake class that requires the existence of a ticket # in every commit
function TicketRequired() {
Ticket.call(this);
this.error = new Error('Commit should include an Assembla ticket #');
}
util.inherits(TicketRequired, Ticket);
TicketRequired.prototype.isValid = function(cb) {
cb(null, false);
}
Ticket.parse = function(text) {
var instances = [];
var cb = function(match, ticket) {
instances.push( new Ticket(ticket, match) );
};
text.replace(/#(-?\d+)\b/gi, cb);
if (!instances.length) {
// maybe should skip merge commits here
instances.push(new TicketRequired());
}
return instances;
}
module.exports = Ticket;
test/references/assembla.js
'use strict';
var assert = require('assert');
var Ticket = require('../../lib/references/assembla');
describe('references/assembla', function() {
it('should validate correctly using the API', function(done) {
this.timeout(5000); // allow enough time
var tickets = Ticket.parse('Change functionality\n\nFixes #13 and #9999 (invalid)');
var ct = 0;
var checkDone = function() {
if (++ct == tickets.length) done();
};
var valid = [true, false];
valid.forEach(function(val, idx) {
tickets[idx].isValid(function(err, valid) {
assert.equal(valid, val, tickets[idx].toString());
checkDone();
});
});
});
it('should require a ticket #', function() {
var tickets = Ticket.parse('Commit message without any ticket ref #');
assert.equal(tickets.length, 1);
assert.equal(tickets[0].error.message, 'Commit should include an Assembla ticket #');
});
});

What exactly am I sending through the parameters?

When doing a XMLHttpRequest and using POST as the form method, what exactly am I sending? I know it should be like send(parameters), parameters = "variable1=Hello", for example. But what if I want to do this:
parameters = "variable1=" + encodeURIComponent(document.getElementById("variable1").value);
variable1 being the id of the HTML form input.
Can I do it like this or do I need to assign the encodeURIComponent value to a javascript variable and send that variable:
var variable2;
parameters = "variable2=" + encodeURIComponent(document.getElementById("variable1").value);
You're suppose to send the object and it's value, but, is it an object from the HTML form, a javascript object or a php object? The problem is I already tried it and I still can't get the encoded input in my database, all I get is the raw input from the user.
BTW, I know it's a pretty dull question, but I feel the need to understand exactly what I'm doing if I want to come up with a solution.
g
function createObject()
{
var request_type;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer")
{
request_type = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
request_type = new XMLHttpRequest();
}
return request_type;
}
var http = createObject();
//INSERT
function insert()
{
var Faculty2 = encodeURIComponent(document.getElementById("Faculty").value);
var Major2 = encodeURIComponent(document.getElementById("Major").value);
var Professor2 = encodeURIComponent(document.getElementById("Professor").value);
var Lastname2 = encodeURIComponent(document.getElementById("Lastname").value);
var Course2 = encodeURIComponent(document.getElementById("Course").value);
var Comments2 = encodeURIComponent(document.getElementById("Comments").value);
var Grade2 = encodeURIComponent(document.getElementById("Grade").value);
var Redflag2 = encodeURIComponent(document.getElementById("Redflag").value);
var Owner2 = encodeURIComponent(document.getElementById("Owner").value);
//Location and parameters of data about to be sent are defined
//Required: verify that all fields are not empty. Use encode URI() to solve some issues about character encoding.
var params = "Faculty=" + Faculty2 + "&Major=" + Major2 + "&Professor=" + Professor2 + "&Lastname=" + Lastname2 + "&Course=" + Course2 + "&Comments=" + Comments2 + "&Grade=" + Grade2 + "&Redflag=" + Redflag2 + "&Owner=" + Owner2;
var url = "prehp/insert.php";
http.open("POST", url, true);
//Technical information about the data
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
//Now, we send the data
http.onreadystatechange = function()
{
if(http.readyState == 4)
{ var answer = http.responseText;
document.getElementById('insert_response').innerHTML = "Ready!" + answer;
}
else
{document.getElementById('insert_response').innerHTML = "Error";
}}
http.send(params);
}
PHP code:
$insertAccounts_sql = "INSERT INTO Information (Faculty, Major, Professor, Lastname, Course, Comments, Grade, Redflag, Owner)
VALUES('$_POST[Faculty]','$_POST[Major]','$_POST[Professor]','$_POST[Lastname]','$_POST[Course]','$_POST[Comments]','$_POST[Grade]','$_POST[Redflag]','$_POST[Owner]')";
$dbq = mysql_query($insertAccounts_sql, $dbc);
if($dbq)
{
print "1 record added: Works very well!";
}
else
if(!$dbq)
{
die('Error: ' . mysql_error());
}
$dbk = mysql_close($dbc);
if($dbk)
{
print "Database closed!";
}
else
if(!$dbk)
{
print "Database not closed!";
}
I did that but the value that the database got was the raw input and not the encoded input. I'm running out of ideas, don't know what else to try. Could it be the settings of the database, can the database be decoding the input before storing it? That seems far-fetched to me, but I've been looking at this from all angles and still can't come up with a fresh answer.
PS: Sorry for posting my comments on the answer area, first timer here.
when creating query strings, it has really nothing to do with objects or anything like that. All you want to be sending is key/value pairs. how you construct that is up to you, but it often neater and more manageable to assign your values to variables first. i.e.
var myVar1Value = encodeURIComponent(document.getElementById('variable1').value);
var myVar2Value = encodeURIComponent(document.getElementById('variable2').value);
var url = "http://www.mydomain.com?" + "var1=" + myVar1Value + "&var2=" + myVar2Value;
It's called a query string, so it's just a string. what you do with it on the server side is what makes the 'magic' happen.
edit: If you're having problems with values, then you should print them to console to verify you are getting what you expect.

Resources