mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
Initial checkin of gettor. This is a program designed to be invoked in a .forward file. It will respond with specific payloads for a given request. It requires that all requests be signed with DKIM. It's not quite finished yet.
svn:r15874
This commit is contained in:
parent
267e61d0f3
commit
81dcfafba3
141
contrib/gettor/gettor.py
Executable file
141
contrib/gettor/gettor.py
Executable file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/python2.5
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
gettor.py by Jacob Appelbaum <jacob@appelbaum.net>
|
||||
This program will hand out Tor via email to supported systems.
|
||||
This program is Free Software released under the GPLv3.
|
||||
|
||||
It is intended to be used in a .forward file as part of a pipe like so:
|
||||
|
||||
cat <<'EOF'> .forward
|
||||
|/usr/local/bin/gettor.py
|
||||
EOF
|
||||
|
||||
You should have a dist/current/ mirror in a directory that gettor can read.
|
||||
Such a mirror can be created like so:
|
||||
|
||||
cd /usr/local/
|
||||
rsync -av rsync://rsync.torproject.org/tor/dist/current tor-dist-current/
|
||||
|
||||
You can keep it updated with a cronjob like so:
|
||||
|
||||
MirrorDir=/usr/local/tor-dist-current/
|
||||
0 3 * * * rsync -a rsync://rsync.torproject.org/tor/dist/current/ $MirrorDir
|
||||
|
||||
You should ensure that for each file and signature pair you wish to
|
||||
distribute, you have created a zip file containing both.
|
||||
|
||||
While this program isn't written in a threaded manner per se, it is designed to function
|
||||
as if it will be called as a pipe many times at once. There is a slight
|
||||
desynchronization with blacklist entry checking and may result in false
|
||||
negatives. This isn't perfect but it is designed to be lightweight. It could
|
||||
be fixed easily with a shared locking system but this isn't implemented yet.
|
||||
|
||||
"""
|
||||
|
||||
__program__ = 'gettor.py'
|
||||
__version__ = '20080713.00'
|
||||
__url__ = 'https://tor-svn.freehaven.net/svn/tor/trunk/contrib/gettor/'
|
||||
__author__ = 'Jacob Appelbaum <jacob@appelbaum.net>'
|
||||
__copyright__ = 'Copyright (c) 2008, Jacob Appelbaum'
|
||||
__license__ = 'See LICENSE for licensing information'
|
||||
|
||||
try:
|
||||
from future import antigravity
|
||||
except ImportError:
|
||||
antigravity = None
|
||||
|
||||
import syslog
|
||||
import gettor_blacklist
|
||||
import gettor_requests
|
||||
import gettor_responses
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
rawMessage = gettor_requests.getMessage()
|
||||
parsedMessage = gettor_requests.parseMessage(rawMessage)
|
||||
|
||||
if not parsedMessage:
|
||||
syslog.syslog("gettor: No parsed message. Dropping message.")
|
||||
print "gettor: No parsed message. Dropping message."
|
||||
exit(1)
|
||||
|
||||
signature = False
|
||||
signature = gettor_requests.verifySignature(rawMessage)
|
||||
print "Signature is : " + str(signature)
|
||||
replyTo = False
|
||||
srcEmail = "gettor@torproject.org"
|
||||
|
||||
# TODO XXX:
|
||||
# Make the zip files and ensure they match packageList
|
||||
# Make each zip file like so:
|
||||
# zip -9 windows-bindle.z \
|
||||
# vidalia-bundle-0.2.0.29-rc-0.1.6.exe \
|
||||
# vidalia-bundle-0.2.0.29-rc-0.1.6.exe.asc
|
||||
#
|
||||
packageList = {
|
||||
"windows-bundle": "/tmp/windows-bundle.z",
|
||||
"macosx-bundle": "/tmp/macosx-bundle.z",
|
||||
"linux-bundle": "/tmp/linux-bundle.z",
|
||||
"source-bundle": "/tmp/source-bundle.z"
|
||||
}
|
||||
|
||||
# XXX TODO: Ensure we have a proper replyTO or bail out (majorly malformed mail).
|
||||
replyTo = gettor_requests.parseReply(parsedMessage)
|
||||
|
||||
if not signature:
|
||||
# Check to see if we've helped them to understand that they need DKIM in the past
|
||||
previouslyHelped = gettor_blacklist.blackList(replyTo)
|
||||
|
||||
if not replyTo:
|
||||
syslog.syslog("No help dispatched. Invalid reply address for user.")
|
||||
print "No help dispatched. Invalid reply address for user."
|
||||
exit(1)
|
||||
|
||||
if not signature and previouslyHelped:
|
||||
syslog.syslog("gettor: Unsigned messaged to gettor by blacklisted user dropped.")
|
||||
print "No help dispatched. Unsigned and unhelped for blacklisted user."
|
||||
exit(1)
|
||||
|
||||
if not signature and not previouslyHelped:
|
||||
# Reply with some help and bail out
|
||||
# Someday call blackList(replyTo)
|
||||
message = """
|
||||
You should try your request again with a provider that implements DKIM. Sorry.
|
||||
"""
|
||||
gettor_responses.sendHelp(message, srcEmail, replyTo)
|
||||
print "attempting to send email from: " + srcEmail + "The mail is sent to: " + replyTo
|
||||
syslog.syslog("gettor: Unsigned messaged to gettor. We issued some help about using DKIM.")
|
||||
print "gettor: Unsigned messaged to gettor. We issued some help about using DKIM."
|
||||
exit(0)
|
||||
|
||||
if signature:
|
||||
syslog.syslog("gettor: Signed messaged to gettor.")
|
||||
print "gettor: Signed messaged to gettor."
|
||||
|
||||
try:
|
||||
print "gettor: Parsing now."
|
||||
package = gettor_requests.parseRequest(parsedMessage, packageList)
|
||||
except:
|
||||
package = None
|
||||
|
||||
if package == "windows-bundle":
|
||||
print "gettor: " + package + " selected."
|
||||
syslog.syslog("gettor: " + package + " selected.")
|
||||
message = "Here's your requested software as a zip file. Please \
|
||||
verify the signature."
|
||||
print "attempting to send email from: " +
|
||||
srcEmail + "The mail is sent to: " + replyTo
|
||||
gettor_responses.sendPackage(message, srcEmail, replyTo, packageList[package])
|
||||
exit(0)
|
||||
else:
|
||||
print "Package request is unknown: " + package
|
||||
message = " Your request was misunderstood. Please select one of the \
|
||||
following packages: " + packageList.keys()
|
||||
|
||||
gettor_responses.sendHelp(message, srcEmail, replyTo)
|
||||
print "attempting to send email from: " + srcEmail + "The mail is sent to: " + replyTo
|
||||
syslog.syslog("gettor: Signed messaged to gettor. We issued some help about proper email formatting.")
|
||||
print "gettor: Signed messaged to gettor. We issued some help about proper email formatting."
|
||||
exit(0)
|
116
contrib/gettor/gettor_blacklist.py
Executable file
116
contrib/gettor/gettor_blacklist.py
Executable file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/python2.5
|
||||
"""
|
||||
This library implements all of the black listing features needed for gettor.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
stateDir = "/tmp/gettor/"
|
||||
blStateDir = stateDir + "bl/"
|
||||
|
||||
def blackList(address, createEntry=False):
|
||||
"""
|
||||
Check to see if an address is on our blacklist. If it is - we'll return true.
|
||||
If requested, we'll attempt to create a blacklist entry and return true if
|
||||
everything works out.
|
||||
"""
|
||||
# XXX TODO: Eventually we may want to sort entries with netcom
|
||||
# style /tmp/gettor/2-digits-of-hash/2-more-digits/rest-of-hash files
|
||||
|
||||
privateAddress = makeAddressPrivate(address)
|
||||
blackListed = lookupBlackListEntry(privateAddress)
|
||||
|
||||
if blackListed:
|
||||
return True
|
||||
elif createEntry:
|
||||
return createBlackListEntry(privateAddress)
|
||||
|
||||
return False
|
||||
|
||||
def lookupBlackListEntry(privateAddress, stateDir="/tmp/gettor/bl/"):
|
||||
""" Check to see if we have a blacklist entry for the given address. """
|
||||
entry = stateDir + str(privateAddress)
|
||||
try:
|
||||
entry = os.stat(entry)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def createBlackListEntry(privateAddress, stateDir="/tmp/gettor/bl/"):
|
||||
""" Create a zero byte file that represents the address in our blacklist. """
|
||||
entry = stateDir + str(privateAddress)
|
||||
stat = None
|
||||
try:
|
||||
stat = os.stat(entry)
|
||||
except OSError:
|
||||
try:
|
||||
fd = open(entry, 'w')
|
||||
fd.close()
|
||||
return True
|
||||
except:
|
||||
print "Entry not found. We were unable to create an entry."
|
||||
return False
|
||||
print "It appears that we already had an entry."
|
||||
return False
|
||||
|
||||
def removeBlackListEntry(privateAddress, stateDir="/tmp/gettor/bl/"):
|
||||
""" Remove the zero byte file that represents an entry in our blacklist."""
|
||||
entry = stateDir + str(privateAddress)
|
||||
stat = None
|
||||
try:
|
||||
entry = os.unlink(entry)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def makeAddressPrivate(address):
|
||||
""" Creates a unique identifier for the user. """
|
||||
hash = hashlib.sha1(address)
|
||||
privateAddress = hash.hexdigest()
|
||||
return privateAddress
|
||||
|
||||
def prepBLStateDir(stateDir = "/tmp/gettor/bl/"):
|
||||
print "Preparing the state directory for gettor."
|
||||
stat = None
|
||||
try:
|
||||
stat = os.stat(stateDir)
|
||||
print "We found a state directory"
|
||||
return True
|
||||
except OSError:
|
||||
try:
|
||||
os.mkdir(stateDir)
|
||||
print "No state directory was found, we created one"
|
||||
return True
|
||||
except:
|
||||
print "Unable to make a state directory"
|
||||
return False
|
||||
|
||||
def blackListtests(address):
|
||||
""" This is a basic evaluation of our blacklist functionality """
|
||||
prepBLStateDir()
|
||||
privateAddress = makeAddressPrivate(address)
|
||||
print "We have a private address of: " + privateAddress
|
||||
print "Testing creation of blacklist entry: "
|
||||
blackListEntry = createBlackListEntry(privateAddress)
|
||||
print blackListEntry
|
||||
print "We're testing a lookup of a known positive blacklist entry: "
|
||||
blackListEntry = lookupBlackListEntry(privateAddress)
|
||||
print blackListEntry
|
||||
print "We're testing removal of a known blacklist entry: "
|
||||
blackListEntry = removeBlackListEntry(privateAddress)
|
||||
print blackListEntry
|
||||
print "We're testing a lookup of a known false blacklist entry: "
|
||||
blackListEntry = lookupBlackListEntry(privateAddress)
|
||||
print blackListEntry
|
||||
print "Now we'll test the higher level blacklist functionality..."
|
||||
print "This should not find an entry in the blacklist: "
|
||||
print blackList(address)
|
||||
print "This should add an entry to the blacklist: "
|
||||
print blackList(address, True)
|
||||
print "This should find the previous addition to the blacklist: "
|
||||
print blackList(address)
|
||||
print "Please ensure the tests match what you would expect for your environment."
|
||||
|
||||
if __name__ == "__main__" :
|
||||
blackListtests("requestingUser@example.com")
|
86
contrib/gettor/gettor_requests.py
Executable file
86
contrib/gettor/gettor_requests.py
Executable file
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/python2.5
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
This library implements all of the email parsing features needed for gettor.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import email
|
||||
import dkim
|
||||
import re
|
||||
|
||||
def getMessage():
|
||||
""" Read the message into a buffer and return it """
|
||||
rawMessage = sys.stdin.read()
|
||||
return rawMessage
|
||||
|
||||
def verifySignature(rawMessage):
|
||||
""" Attempt to verify the DKIM signature of a message and return a positive or negative status """
|
||||
signature = False
|
||||
|
||||
# TODO XXX:
|
||||
# This should catch DNS exceptions and fail to verify if we have a
|
||||
# dns timeout
|
||||
if dkim.verify(rawMessage):
|
||||
signature = True
|
||||
return signature
|
||||
else:
|
||||
return signature
|
||||
|
||||
def parseMessage(message):
|
||||
""" parse an email message and return a parsed email object """
|
||||
return email.message_from_string(message)
|
||||
|
||||
def parseReply(parsedMessage):
|
||||
""" Return an email address that we want to email """
|
||||
# TODO XXX:
|
||||
# Scrub this data
|
||||
address = parsedMessage["from"]
|
||||
return address
|
||||
|
||||
def parseRequest(parsedMessage, packages):
|
||||
""" This parses the request and returns the first specific package name for
|
||||
sending. If we do not understand the request, we return None as the package
|
||||
name."""
|
||||
# XXX TODO:
|
||||
# Should we pick only the first line of the email body. Drop the rest?
|
||||
# It may be too unfriendly to our users
|
||||
for line in email.Iterators.body_line_iterator(parsedMessage):
|
||||
for package in packages.keys():
|
||||
print "Line is: " + line
|
||||
print "Package is " + package
|
||||
match = re.match(package, line)
|
||||
if match:
|
||||
return package
|
||||
# If we get here, we didn't find a package we're currently serving
|
||||
return None
|
||||
|
||||
if __name__ == "__main__" :
|
||||
""" Give us an email to understand what we think of it. """
|
||||
packageList = {
|
||||
"windows-bundle": "/tmp/windows-bundle.z",
|
||||
"macosx-bundle": "/tmp/macosx-bundle.z",
|
||||
"linux-bundle": "/tmp/linux-bundle.z",
|
||||
"source-bundle": "/tmp/source-bundle.z"
|
||||
}
|
||||
|
||||
print "Fetching raw message."
|
||||
rawMessage = getMessage()
|
||||
# This doesn't work without DNS ( no wifi on board current airplane )
|
||||
print "Verifying signature of message."
|
||||
signature = verifySignature(rawMessage)
|
||||
print "Parsing Message."
|
||||
parsedMessage = parseMessage(rawMessage)
|
||||
print "Parsing reply."
|
||||
parsedReply = parseReply(parsedMessage)
|
||||
print "Parsing package request."
|
||||
package = parseRequest(parsedMessage, packageList)
|
||||
if package == None:
|
||||
package = "help"
|
||||
else:
|
||||
package = packageList[package]
|
||||
|
||||
print "The signature status of the email is: " + str(signature)
|
||||
print "The email requested the following reply address: " + parsedReply
|
||||
print "It looks like the email requested the following package: " + package
|
||||
print "We would select the following package file: " + package
|
72
contrib/gettor/gettor_responses.py
Executable file
72
contrib/gettor/gettor_responses.py
Executable file
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/python2.5
|
||||
# -*- coding: utf-8 -*-
|
||||
""" This library implements all of the email replying features needed for gettor. """
|
||||
|
||||
import smtplib
|
||||
import MimeWriter
|
||||
import syslog
|
||||
import StringIO
|
||||
import base64
|
||||
|
||||
def sendHelp(message, source, destination):
|
||||
""" Send a helpful message to the user interacting with us """
|
||||
help = constructMessage(message, source, destination)
|
||||
try:
|
||||
print "Attempting to send the following message: "
|
||||
status = sendMessage(help, source, destination)
|
||||
except:
|
||||
print "Message sending failed."
|
||||
status = False
|
||||
return status
|
||||
|
||||
def sendPackage(message, source, destination, filelist):
|
||||
""" Send a message with an attachment to the user interacting with us """
|
||||
package = constructMessage(message, source, destination, filelist)
|
||||
try:
|
||||
print "Attempting to send the following message: "
|
||||
status = sendMessage(package, destination)
|
||||
except:
|
||||
print "Message sending failed."
|
||||
status = False
|
||||
return status
|
||||
|
||||
def constructMessage(messageText, ourAddress, recipient, fileList=None, fileName="requested-files.z"):
|
||||
""" Construct a multi-part mime message, including only the first part
|
||||
with plaintext."""
|
||||
|
||||
message = StringIO.StringIO()
|
||||
mime = MimeWriter.MimeWriter(message)
|
||||
mime.addheader('MIME-Version', '1.0')
|
||||
mime.addheader('Subject', 'Your request has been processed')
|
||||
mime.addheader('To', recipient)
|
||||
mime.addheader('From', ourAddress)
|
||||
mime.startmultipartbody('mixed')
|
||||
|
||||
firstPart = mime.nextpart()
|
||||
emailBody = firstPart.startbody('text/plain')
|
||||
emailBody.write(messageText)
|
||||
|
||||
# Add a file if we have one
|
||||
if fileList:
|
||||
# XXX TODO: Iterate over each file eventually
|
||||
filePart = mime.nextpart()
|
||||
filePart.addheader('Content-Transfer-Encoding', 'base64')
|
||||
emailBody = filePart.startbody('application/zip; name=%s' % fileName)
|
||||
base64.encode(open(fileList, 'rb'), emailBody)
|
||||
|
||||
# Now end the mime messsage
|
||||
mime.lastpart()
|
||||
return message
|
||||
|
||||
def sendMessage(message, dst, src="gettor@torproject.org", smtpserver="localhost:2700"):
|
||||
try:
|
||||
smtp = smtplib.SMTP(smtpserver)
|
||||
smtp.sendmail(src, dst, message.getvalue())
|
||||
smtp.quit()
|
||||
status = True
|
||||
except:
|
||||
return False
|
||||
|
||||
return status
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
X-Account-Key: account6
|
||||
X-UIDL: 1215752284.31537.faustus,S=1469
|
||||
X-Mozilla-Status: 0001
|
||||
X-Mozilla-Status2: 02000000
|
||||
Return-Path: <jacob@appelbaum.net>
|
||||
Delivered-To: jpopped@appelbaum.net
|
||||
Received: (qmail 31535 invoked by uid 89); 11 Jul 2008 04:58:04 -0000
|
||||
Delivered-To: appelbaum.net-jacob@appelbaum.net
|
||||
Received: (qmail 31531 invoked by uid 89); 11 Jul 2008 04:58:04 -0000
|
||||
Received: from unknown (HELO moria.seul.org) (128.31.0.34)
|
||||
by 0 with (DHE-RSA-AES256-SHA encrypted) SMTP; 11 Jul 2008 04:58:04 -0000
|
||||
Received-SPF: none (0: domain at appelbaum.net does not designate permitted sender hosts)
|
||||
Received: by moria.seul.org (Postfix)
|
||||
id F09581415CD3; Fri, 11 Jul 2008 00:55:45 -0400 (EDT)
|
||||
Delivered-To: gettor@seul.org
|
||||
Received: from mail.lostinthenoise.net (mail.lostinthenoise.net [64.142.98.226])
|
||||
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
|
||||
(No client certificate requested)
|
||||
by moria.seul.org (Postfix) with ESMTP id C464A140F476
|
||||
for <gettor@torproject.org>; Fri, 11 Jul 2008 00:55:45 -0400 (EDT)
|
||||
Received: (qmail 31524 invoked by uid 89); 11 Jul 2008 04:58:02 -0000
|
||||
Received: from unknown (HELO ?127.0.0.1?) (64.142.98.226)
|
||||
by 0 with (DHE-RSA-AES256-SHA encrypted) SMTP; 11 Jul 2008 04:58:02 -0000
|
||||
Message-ID: <4876E7D0.5050201@appelbaum.net>
|
||||
Date: Thu, 10 Jul 2008 21:55:44 -0700
|
||||
From: Jacob Appelbaum <jacob@appelbaum.net>
|
||||
User-Agent: Icedove 1.5.0.14eol (X11/20080509)
|
||||
MIME-Version: 1.0
|
||||
To: gettor@torproject.org
|
||||
Subject: negative DKIM signature
|
||||
X-Enigmail-Version: 0.94.2.0
|
||||
OpenPGP: id=9D0FACE4;
|
||||
url=http://www.appelbaum.net/gpg.asc
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
source-bundle
|
||||
|
||||
|
39
contrib/gettor/sample-emails/negative-DKIM-header.eml
Normal file
39
contrib/gettor/sample-emails/negative-DKIM-header.eml
Normal file
@ -0,0 +1,39 @@
|
||||
X-Account-Key: account6
|
||||
X-UIDL: 1215752284.31537.faustus,S=1469
|
||||
X-Mozilla-Status: 0001
|
||||
X-Mozilla-Status2: 02000000
|
||||
Return-Path: <jacob@appelbaum.net>
|
||||
Delivered-To: jpopped@appelbaum.net
|
||||
Received: (qmail 31535 invoked by uid 89); 11 Jul 2008 04:58:04 -0000
|
||||
Delivered-To: appelbaum.net-jacob@appelbaum.net
|
||||
Received: (qmail 31531 invoked by uid 89); 11 Jul 2008 04:58:04 -0000
|
||||
Received: from unknown (HELO moria.seul.org) (128.31.0.34)
|
||||
by 0 with (DHE-RSA-AES256-SHA encrypted) SMTP; 11 Jul 2008 04:58:04 -0000
|
||||
Received-SPF: none (0: domain at appelbaum.net does not designate permitted sender hosts)
|
||||
Received: by moria.seul.org (Postfix)
|
||||
id F09581415CD3; Fri, 11 Jul 2008 00:55:45 -0400 (EDT)
|
||||
Delivered-To: gettor@seul.org
|
||||
Received: from mail.lostinthenoise.net (mail.lostinthenoise.net [64.142.98.226])
|
||||
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
|
||||
(No client certificate requested)
|
||||
by moria.seul.org (Postfix) with ESMTP id C464A140F476
|
||||
for <gettor@torproject.org>; Fri, 11 Jul 2008 00:55:45 -0400 (EDT)
|
||||
Received: (qmail 31524 invoked by uid 89); 11 Jul 2008 04:58:02 -0000
|
||||
Received: from unknown (HELO ?127.0.0.1?) (64.142.98.226)
|
||||
by 0 with (DHE-RSA-AES256-SHA encrypted) SMTP; 11 Jul 2008 04:58:02 -0000
|
||||
Message-ID: <4876E7D0.5050201@appelbaum.net>
|
||||
Date: Thu, 10 Jul 2008 21:55:44 -0700
|
||||
From: Jacob Appelbaum <jacob@appelbaum.net>
|
||||
User-Agent: Icedove 1.5.0.14eol (X11/20080509)
|
||||
MIME-Version: 1.0
|
||||
To: gettor@torproject.org
|
||||
Subject: negative DKIM signature
|
||||
X-Enigmail-Version: 0.94.2.0
|
||||
OpenPGP: id=9D0FACE4;
|
||||
url=http://www.appelbaum.net/gpg.asc
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
testing
|
||||
|
||||
|
57
contrib/gettor/sample-emails/positive-DKIM-header.eml
Normal file
57
contrib/gettor/sample-emails/positive-DKIM-header.eml
Normal file
@ -0,0 +1,57 @@
|
||||
X-Account-Key: account6
|
||||
X-UIDL: 1214981061.25808.faustus,S=2285
|
||||
X-Mozilla-Status: 0001
|
||||
X-Mozilla-Status2: 02000000
|
||||
Return-Path: <ioerror@gmail.com>
|
||||
Delivered-To: jpopped@appelbaum.net
|
||||
Received: (qmail 25806 invoked by uid 89); 2 Jul 2008 06:44:21 -0000
|
||||
Delivered-To: appelbaum.net-jacob@appelbaum.net
|
||||
Received: (qmail 25804 invoked by uid 89); 2 Jul 2008 06:44:21 -0000
|
||||
Received: from unknown (HELO wa-out-1112.google.com) (209.85.146.180)
|
||||
by 0 with SMTP; 2 Jul 2008 06:44:21 -0000
|
||||
Received-SPF: pass (0: SPF record at _spf.google.com designates 209.85.146.180 as permitted sender)
|
||||
Received: by wa-out-1112.google.com with SMTP id j40so170432wah.1
|
||||
for <jacob@appelbaum.net>; Tue, 01 Jul 2008 23:42:01 -0700 (PDT)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=gmail.com; s=gamma;
|
||||
h=domainkey-signature:received:received:message-id:date:from:to
|
||||
:subject:mime-version:content-type;
|
||||
bh=IvFqNkffeoST7vamh2ytuq/b7GpLhg2hStTrQq3I3rE=;
|
||||
b=xQR0hE/J4AXpAqH1UDXTtDrU9Izc6WM8vtFudRBzldWYyRx3Vvfh2I2Opu8+O6wbAv
|
||||
jlDi18anUMbZqlIGSgGOxvXW4CltpX/SFZm1aGL4AisQ1Bi5xEqlrc8OnX3sA2xKeM3g
|
||||
KWsWm+GVSMI4XAqnY9FYAfPx4DmOAfkdMyWCU=
|
||||
DomainKey-Signature: a=rsa-sha1; c=nofws;
|
||||
d=gmail.com; s=gamma;
|
||||
h=message-id:date:from:to:subject:mime-version:content-type;
|
||||
b=kyzDtGRDbiC5y4Bz/ylQjyHOChiOP2A6QDzybsVXc0C1hjHLImOQYR8gOxcRY+mRkN
|
||||
1xpBaEF4UloZAxTb79khRRp4TWmjT1DagtLx2MFzIj/F6awtdE/9U3p4QyKr8S43tGcE
|
||||
ET26BSfT5u9zrXblVVAP3JedMPZ8mlIGQxyDs=
|
||||
Received: by 10.115.90.1 with SMTP id s1mr6711509wal.51.1214980921268;
|
||||
Tue, 01 Jul 2008 23:42:01 -0700 (PDT)
|
||||
Received: by 10.114.184.16 with HTTP; Tue, 1 Jul 2008 23:41:57 -0700 (PDT)
|
||||
Message-ID: <7fadd8130807012341n3b3af401mbdb4a29c80310bd3@mail.gmail.com>
|
||||
Date: Tue, 1 Jul 2008 23:41:57 -0700
|
||||
From: "Jacob Applebaum" <ioerror@gmail.com>
|
||||
To: jacob@appelbaum.net
|
||||
Subject: Positive DKIM header
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="----=_Part_462_28562233.1214980917793"
|
||||
|
||||
------=_Part_462_28562233.1214980917793
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: inline
|
||||
|
||||
This email should have a positive DKIM header.
|
||||
|
||||
------=_Part_462_28562233.1214980917793
|
||||
Content-Type: text/html; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: inline
|
||||
|
||||
This email should have a positive DKIM header.<br>
|
||||
|
||||
------=_Part_462_28562233.1214980917793--
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user