mirror of https://github.com/apache/poi.git
you can now protect files with writeProtectWorkbook
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@557333 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a21c4c4594
commit
4f804edf40
|
@ -512,6 +512,9 @@ public class BiffViewer {
|
|||
case NoteRecord.sid:
|
||||
retval = new NoteRecord( in );
|
||||
break;
|
||||
case FileSharingRecord.sid:
|
||||
retval = new FileSharingRecord( in );
|
||||
break;
|
||||
default:
|
||||
retval = new UnknownRecord( in );
|
||||
}
|
||||
|
|
|
@ -44,13 +44,13 @@ import java.util.Locale;
|
|||
* before even attempting to use this.
|
||||
*
|
||||
*
|
||||
* @author Luc Girardin (luc dot girardin at macrofocus dot com)
|
||||
* @author Sergei Kozello (sergeikozello at mail.ru)
|
||||
* @author Shawn Laubach (slaubach at apache dot org) (Data Formats)
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @author Sergei Kozello (sergeikozello at mail.ru)
|
||||
* @author Luc Girardin (luc dot girardin at macrofocus dot com)
|
||||
* @author Dan Sherman (dsherman at isisph.com)
|
||||
* @author Brian Sanders (bsanders at risklabs dot com) - custom palette
|
||||
* @author Dan Sherman (dsherman at isisph.com)
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook
|
||||
* @version 1.0-pre
|
||||
*/
|
||||
|
@ -101,6 +101,9 @@ public class Workbook implements Model
|
|||
private DrawingManager2 drawingManager;
|
||||
private List escherBSERecords = new ArrayList(); // EscherBSERecord
|
||||
private WindowOneRecord windowOne;
|
||||
private FileSharingRecord fileShare;
|
||||
private WriteAccessRecord writeAccess;
|
||||
private WriteProtectRecord writeProtect;
|
||||
|
||||
private static POILogger log = POILogFactory.getLogger(Workbook.class);
|
||||
|
||||
|
@ -220,7 +223,22 @@ public class Workbook implements Model
|
|||
case WindowOneRecord.sid:
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(DEBUG, "found WindowOneRecord at " + k);
|
||||
retval.windowOne = (WindowOneRecord) rec;
|
||||
retval.windowOne = (WindowOneRecord) rec;
|
||||
break;
|
||||
case WriteAccessRecord.sid:
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(DEBUG, "found WriteAccess at " + k);
|
||||
retval.writeAccess = (WriteAccessRecord) rec;
|
||||
break;
|
||||
case WriteProtectRecord.sid:
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(DEBUG, "found WriteProtect at " + k);
|
||||
retval.writeProtect = (WriteProtectRecord) rec;
|
||||
break;
|
||||
case FileSharingRecord.sid:
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
log.log(DEBUG, "found FileSharing at " + k);
|
||||
retval.fileShare = (FileSharingRecord) rec;
|
||||
default :
|
||||
}
|
||||
records.add(rec);
|
||||
|
@ -2235,5 +2253,70 @@ public class Workbook implements Model
|
|||
return drawingManager;
|
||||
}
|
||||
|
||||
public WriteProtectRecord getWriteProtect() {
|
||||
if (this.writeProtect == null) {
|
||||
this.writeProtect = new WriteProtectRecord();
|
||||
int i = 0;
|
||||
for (i = 0;
|
||||
i < records.size() && !(records.get(i) instanceof BOFRecord);
|
||||
i++) {
|
||||
}
|
||||
records.add(i+1,this.writeProtect);
|
||||
}
|
||||
return this.writeProtect;
|
||||
}
|
||||
|
||||
public WriteAccessRecord getWriteAccess() {
|
||||
if (this.writeAccess == null) {
|
||||
this.writeAccess = (WriteAccessRecord)createWriteAccess();
|
||||
int i = 0;
|
||||
for (i = 0;
|
||||
i < records.size() && !(records.get(i) instanceof InterfaceEndRecord);
|
||||
i++) {
|
||||
}
|
||||
records.add(i+1,this.writeAccess);
|
||||
}
|
||||
return this.writeAccess;
|
||||
}
|
||||
|
||||
public FileSharingRecord getFileSharing() {
|
||||
if (this.fileShare == null) {
|
||||
this.fileShare = new FileSharingRecord();
|
||||
int i = 0;
|
||||
for (i = 0;
|
||||
i < records.size() && !(records.get(i) instanceof WriteAccessRecord);
|
||||
i++) {
|
||||
}
|
||||
records.add(i+1,this.fileShare);
|
||||
}
|
||||
return this.fileShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* protect a workbook with a password (not encypted, just sets writeprotect
|
||||
* flags and the password.
|
||||
* @param password to set
|
||||
*/
|
||||
public void writeProtectWorkbook( String password, String username ) {
|
||||
int protIdx = -1;
|
||||
FileSharingRecord frec = getFileSharing();
|
||||
WriteAccessRecord waccess = getWriteAccess();
|
||||
WriteProtectRecord wprotect = getWriteProtect();
|
||||
frec.setReadOnly((short)1);
|
||||
frec.setPassword(FileSharingRecord.hashPassword(password));
|
||||
frec.setUsername(username);
|
||||
waccess.setUsername(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the write protect flag
|
||||
*/
|
||||
public void unwriteProtectWorkbook() {
|
||||
records.remove(fileShare);
|
||||
records.remove(writeProtect);
|
||||
fileShare = null;
|
||||
writeProtect = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,11 @@ public class WorkbookRecordList
|
|||
return records.iterator();
|
||||
}
|
||||
|
||||
public void remove( Object record ) {
|
||||
int i = records.indexOf(record);
|
||||
this.remove(i);
|
||||
}
|
||||
|
||||
public void remove( int pos )
|
||||
{
|
||||
records.remove(pos);
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Title: FileSharing<P>
|
||||
* Description: stores the encrypted readonly for a workbook (write protect)
|
||||
* REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
*/
|
||||
|
||||
public class FileSharingRecord extends Record {
|
||||
public final static short sid = 0x5b;
|
||||
private short field_1_readonly;
|
||||
private short field_2_password;
|
||||
private byte field_3_username_length;
|
||||
private short field_4_unknown; // not documented
|
||||
private String field_5_username;
|
||||
|
||||
public FileSharingRecord() {}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a FileSharing record and sets its fields appropriately.
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public FileSharingRecord(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
protected void validateSid(short id) {
|
||||
if (id != sid) {
|
||||
throw new RecordFormatException("NOT A FILESHARING RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
protected void fillFields(RecordInputStream in) {
|
||||
field_1_readonly = in.readShort();
|
||||
field_2_password = in.readShort();
|
||||
field_3_username_length = in.readByte();
|
||||
field_4_unknown = in.readShort();
|
||||
field_5_username = in.readCompressedUnicode(field_3_username_length);
|
||||
}
|
||||
|
||||
//this is the world's lamest "security". thanks to Wouter van Vugt for making me
|
||||
//not have to try real hard. -ACO
|
||||
public static short hashPassword(String password) {
|
||||
byte[] passwordCharacters = password.getBytes();
|
||||
int hash = 0;
|
||||
if (passwordCharacters.length > 0) {
|
||||
int charIndex = passwordCharacters.length;
|
||||
while (charIndex-- > 0) {
|
||||
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
|
||||
hash ^= passwordCharacters[charIndex];
|
||||
}
|
||||
// also hash with charcount
|
||||
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
|
||||
hash ^= passwordCharacters.length;
|
||||
hash ^= (0x8000 | ('N' << 8) | 'K');
|
||||
}
|
||||
return (short)hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the readonly flag
|
||||
*
|
||||
* @param readonly 1 for true, not 1 for false
|
||||
*/
|
||||
public void setReadOnly(short readonly) {
|
||||
field_1_readonly = readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the readonly
|
||||
*
|
||||
* @return short representing if this is read only (1 = true)
|
||||
*/
|
||||
public short getReadOnly() {
|
||||
return field_1_readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hashed password
|
||||
*/
|
||||
public void setPassword(short password) {
|
||||
field_2_password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns password hashed with hashPassword() (very lame)
|
||||
*/
|
||||
public short getPassword() {
|
||||
return field_2_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns byte representing the length of the username field
|
||||
*/
|
||||
public byte getUsernameLength() {
|
||||
return field_3_username_length ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byte representing the length of the username field
|
||||
*/
|
||||
public void setUsernameLength(byte length) {
|
||||
this.field_3_username_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns username of the user that created the file
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.field_5_username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param username of the user that created the file
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.field_5_username = username;
|
||||
this.field_3_username_length = (byte)username.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return short value of a "bonus field" in Excel that was not doc'd
|
||||
*/
|
||||
public short getUnknown() {
|
||||
return field_4_unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param unknown field value to set (bonus field that is not doc'd)
|
||||
*/
|
||||
public void setUnknown(short unk) {
|
||||
field_4_unknown = unk;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[FILESHARING]\n");
|
||||
buffer.append(" .readonly = ")
|
||||
.append(getReadOnly() == 1 ? "true" : "false").append("\n");
|
||||
buffer.append(" .password = ")
|
||||
.append(Integer.toHexString(getPassword())).append("\n");
|
||||
buffer.append(" .userlen = ")
|
||||
.append(Integer.toHexString(getUsernameLength())).append("\n");
|
||||
buffer.append(" .unknown = ")
|
||||
.append(Integer.toHexString(getUnknown())).append("\n");
|
||||
buffer.append(" .username = ")
|
||||
.append(getUsername()).append("\n");
|
||||
buffer.append("[/FILESHARING]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int serialize(int offset, byte [] data) {
|
||||
LittleEndian.putShort(data, 0 + offset, sid);
|
||||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
|
||||
LittleEndian.putShort(data, 4 + offset, getReadOnly());
|
||||
LittleEndian.putShort(data, 6 + offset, getPassword());
|
||||
data[ 8 + offset ] = getUsernameLength();
|
||||
LittleEndian.putShort(data, 9 + offset, getUnknown());
|
||||
StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
|
||||
return getRecordSize();
|
||||
}
|
||||
|
||||
public int getRecordSize() {
|
||||
return 11+getUsernameLength();
|
||||
}
|
||||
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone this record.
|
||||
*/
|
||||
public Object clone() {
|
||||
FileSharingRecord clone = new FileSharingRecord();
|
||||
clone.setReadOnly(field_1_readonly);
|
||||
clone.setPassword(field_2_password);
|
||||
clone.setUsernameLength(field_3_username_length);
|
||||
clone.setUnknown(field_4_unknown);
|
||||
clone.setUsername(field_5_username);
|
||||
return clone;
|
||||
}
|
||||
|
||||
}
|
|
@ -74,7 +74,7 @@ public class RecordFactory
|
|||
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class,
|
||||
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class,
|
||||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
|
||||
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class
|
||||
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, FileSharingRecord.class
|
||||
};
|
||||
}
|
||||
private static Map recordsMap = recordsToMap(records);
|
||||
|
|
|
@ -1372,6 +1372,22 @@ public class HSSFWorkbook
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* protect a workbook with a password (not encypted, just sets writeprotect
|
||||
* flags and the password.
|
||||
* @param password to set
|
||||
*/
|
||||
public void writeProtectWorkbook( String password, String username ) {
|
||||
this.workbook.writeProtectWorkbook(password, username);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the write protect flag
|
||||
*/
|
||||
public void unwriteProtectWorkbook() {
|
||||
this.workbook.unwriteProtectWorkbook();
|
||||
}
|
||||
|
||||
private byte[] newUID()
|
||||
{
|
||||
byte[] bytes = new byte[16];
|
||||
|
|
Loading…
Reference in New Issue